/**
 * @file exercise.c
 *
 */

/*********************
*      INCLUDES
*********************/
#include "exercise.h"

#if USE_LV_WATCH_EXERCISE != 0

#include "exercise_sport_test.h"

/*********************
*      DEFINES
*********************/
#define EXERCISE_HR_ARC_ANGLE               (270)
#if EXERCISE_TEST_MODE != 0
#define EXERCISE_MAX_HR_ZONE_NUM            (EXERCISE_TEST_HR_ZONE_NUM)
#else
#define EXERCISE_MAX_HR_ZONE_NUM            (5)
#endif

#define EXERCISE_TRANING_EFFECT_ARC_ANGLE   (136)

/**********************
*      TYPEDEFS
**********************/
typedef struct
{
    lv_watch_obj_ext_t old_ext;
    lv_obj_t * btn;
    lv_obj_t * bat_cont;
    lv_obj_t * time_label;
    lv_obj_t * hr_label;
    lv_obj_t * gps_cont;
    lv_obj_t * note_label;
    lv_obj_t * wait_gps_cont;
    lv_task_t * update_task;
    exercise_item_t * item;
} exercise_sport_ext_t;

typedef struct
{
    lv_tileview_ext_t old_ext;
    lv_point_t * valid_pos;
    lv_obj_t * leds_cont;
    lv_obj_t * pause_cont;
    lv_obj_t * stop_cont;
#if USE_LV_WATCH_AUDIO_PLAYER != 0
    lv_obj_t * audio_player_cont;
#endif
    exercise_item_t * item;
    bool is_wakey;
} exercise_tileview_ext_t;

typedef struct
{
    lv_list_ext_t old_ext;
    lv_task_t * update_task;
    uint32_t start_time; // in seconds
} exercise_list_ext_t;

typedef struct
{
    lv_btn_ext_t old_ext;
    lv_obj_t * label[EXERCISE_MAX_ITEM_NUM_PER_START_UI];
    lv_obj_t * time_label;
    lv_obj_t * hr_state_cont;
    lv_obj_t * pointer_img;
    EXERCISE_ARC_TYPE_T arc_type;
    uint8_t color_index; // invalid if 0xff
    gif_info_t * info;
} exercise_btn_ext_t;

/**********************
*  STATIC PROTOTYPES
**********************/
#if EXERCISE_TEST_MODE != 0
static void exercise_sport_prepare_cnf(void);
#endif

/**********************
*  STATIC VARIABLES
**********************/

/**********************
*      MACROS
**********************/

/**********************
 *   STATIC FUNCTIONS
 **********************/
#if EXERCISE_TEST_MODE != 0
static EXERCISE_TYPE_T exercise_get_sport_type(EXERCISE_TEST_TYPE_T sport_type)
{
    EXERCISE_TYPE_T type = EXERCISE_TYPE_NONE;
    switch(sport_type) {
    case EXERCISE_TEST_TYPE_OUTDOOR_RUNNING:
        type = EXERCISE_TYPE_OUTDOOR_RUNNING;
        break;
    case EXERCISE_TEST_TYPE_OUTDOOR_CYCLING:
        type = EXERCISE_TYPE_OUTDOOR_CYCLING;
        break;
    case EXERCISE_TEST_TYPE_FREE_TRAINING:
        type = EXERCISE_TYPE_FREE_TRAINING;
        break;
    case EXERCISE_TEST_TYPE_WALKING:
        type = EXERCISE_TYPE_WALKING;
        break;
    default:
        printf("%s: warning, invalid sport type %d\n", __FUNCTION__, sport_type);
        break;
    }
    return(type);
}
#endif

static void exercise_sport_prepare_req(EXERCISE_TYPE_T type)
{
#if EXERCISE_TEST_MODE != 0
    EXERCISE_TEST_TYPE_T sport_type;
    switch(type) {
    case EXERCISE_TYPE_OUTDOOR_RUNNING:
        sport_type = EXERCISE_TEST_TYPE_OUTDOOR_RUNNING;
        break;
    case EXERCISE_TYPE_OUTDOOR_CYCLING:
        sport_type = EXERCISE_TEST_TYPE_OUTDOOR_CYCLING;
        break;
    case EXERCISE_TYPE_FREE_TRAINING:
        sport_type = EXERCISE_TEST_TYPE_FREE_TRAINING;
        break;
    case EXERCISE_TYPE_WALKING:
        sport_type = EXERCISE_TEST_TYPE_WALKING;
        break;
    default:
        printf("%s: warning, invalid sport type %d\n", __FUNCTION__, type);
        return;
    }
    exercise_test_sport_prepare_req(sport_type, exercise_sport_prepare_cnf);
#else
#endif
}

#if EXERCISE_TEST_MODE != 0
static void exercise_get_sport_data(exercise_test_sport_data_t * data)
{
    exercise_test_get_sport_data(data);
}
#endif

static void exercise_sport_start_req(void)
{
#if EXERCISE_TEST_MODE != 0
    exercise_test_sport_start_req();
#else
#endif
}

static void exercise_sport_stop_req(void)
{
#if EXERCISE_TEST_MODE != 0
    if(exercise_test_prepare_to_stop_sport()) {
        exercise_test_record_t data = {};
        exercise_test_sport_stop_req(&data);
        exercise_ext_t * ext = exercise_get_ext(ACT_ID_EXERCISE);
        char txt[EXERCISE_MAX_TXT_LEN] = {};
        uint8_t hours = (uint8_t)(data.recovery_time / 3600);
        if(1 < hours) {
            snprintf(txt, EXERCISE_MAX_TXT_LEN, "%s %d %s",
                     (char *)lv_lang_get_text(WATCH_TEXT_ID_RECOVERY_TIME), hours,
                     (char *)lv_lang_get_text(WATCH_TEXT_ID_ACT_HOURS));
        } else {
            snprintf(txt, EXERCISE_MAX_TXT_LEN, "%s %d %s",
                     (char *)lv_lang_get_text(WATCH_TEXT_ID_RECOVERY_TIME), hours,
                     (char *)lv_lang_get_text(WATCH_TEXT_ID_ACT_HOUR));
        }
        hal_rtc_t time;
        Hal_Rtc_Gettime(&time);
        exercise_nv_main_t nv = {};
        nv.last_exercise_end_time = time_to_seconds(&time);
        nv.recovery_time = data.recovery_time;
        lv_watch_set_free_num(ext->recovery_time_label, nv.recovery_time);
        exercise_write_nv(EXERCISE_TYPE_NONE, 0, 2 * sizeof(uint32_t), &nv,
                          EXERCISE_WRITE_NV_MODE_REPLACE);
        if(NULL == lv_anim_get(ext->recovery_time_label, NULL)) {
            exercise_start_recovery_time_anim(ext);
        }

        if(data.pace) {
            lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_EXERCISE_SPORT);
            lv_obj_t * tileview = lv_obj_get_child_back(activity_obj, NULL);
            exercise_tileview_ext_t * tileview_ext = lv_obj_get_ext_attr(tileview);
            exercise_sport_info_t sport_info;
            exercise_get_sport_info(tileview_ext->item->type, &sport_info);
            uint32_t offset = exercise_get_nv_offset(sport_info.setting_item_bitmap,
                                                     EXERCISE_SETTING_ITEM_TYPE_INTEL_RUN_COMP);
            if(0xFFFFFFFF != offset) {
                exercise_nv_intel_run_comp_t * nv_intel_run_comp
                    = (exercise_nv_intel_run_comp_t *)(&tileview_ext->item->data[offset]);
                nv_intel_run_comp->last_value = data.aver_pace;
                if(0 == nv_intel_run_comp->best_value) {
                    nv_intel_run_comp->best_value = data.aver_pace;
                } else if(data.aver_pace < nv_intel_run_comp->best_value) {
                    nv_intel_run_comp->best_value = data.aver_pace;
                }
                if(EXERCISE_GOAL_PACE_TYPE_LAST_TIME == nv_intel_run_comp->type) {
                    nv_intel_run_comp->value = nv_intel_run_comp->last_value;
                } else if(EXERCISE_GOAL_PACE_TYPE_SINGLE_BEST == nv_intel_run_comp->type) {
                    nv_intel_run_comp->value = nv_intel_run_comp->best_value;
                }
                exercise_write_nv(tileview_ext->item->type, offset, sizeof(exercise_nv_intel_run_comp_t),
                                  nv_intel_run_comp, EXERCISE_WRITE_NV_MODE_REPLACE);
            }
        }

#if USE_LV_WATCH_EXERCISE_RECORD != 0
        exercise_record_t record = {};
        record.base.sport_type = exercise_get_sport_type(data.type);
        record.base.end_time = nv.last_exercise_end_time;

        record.synthesis.total_disctance = data.total_disctance;
        record.synthesis.sport_time = data.sport_time;
        record.synthesis.calorie = data.calorie;

        record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_HR_CURVE;
        record.hr_curve.max_hr = data.max_hr;
        record.hr_curve.min_hr = data.min_hr;
        record.hr_curve.aver_hr = data.aver_hr;
        Hal_Mem_Copy(record.hr_curve.hr, data.hr,
                     sizeof(uint8_t) * EXERCISE_RECORD_CURVE_NODE_NUM);

        record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_HR_ZONE;
        Hal_Mem_Copy(record.hr_zone.time, data.hr_zone_time,
                     sizeof(uint16_t) * EXERCISE_RECORD_HR_ZONE_NUM);

        record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_TRAINING_EFFECT;
        record.training_effect.aerobic_training_value = data.aerobic_training_value;
        record.training_effect.anaerobic_training_value = data.anaerobic_training_value;

        record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_RECOVERY_TIME;
        record.recovery_time.value = data.recovery_time;
        record.recovery_time.max_value = data.max_recovery_time;

        if(data.speed) {
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_SPEED;
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_SPEED_CURVE;
            record.speed.top_speed = data.speed->top_speed;
            record.speed.aver_speed = data.aver_speed;
            record.speed.aver_pace = data.aver_pace;
            Hal_Mem_Copy(record.speed_curve.speed, data.speed->speed,
                         sizeof(uint16_t) * EXERCISE_RECORD_CURVE_NODE_NUM);
            Hal_Mem_Free(data.speed);
        }
        if(data.pace) {
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_PACE;
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_PACE_CURVE;
            record.pace.top_pace = data.pace->max_pace;
            record.pace.aver_speed = data.aver_speed;
            record.pace.aver_pace = data.aver_pace;
            record.pace_curve.max_pace = data.pace->max_pace;
            record.pace_curve.aver_pace = data.aver_pace;
            Hal_Mem_Copy(record.pace_curve.pace, data.pace->pace,
                         sizeof(uint16_t) * EXERCISE_RECORD_CURVE_NODE_NUM);
            Hal_Mem_Free(data.pace);
        }
        if(data.step) {
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_STEP;
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_STRIDE_FREQ_CURVE;
            record.step.step_number = data.step->step_number;
            record.step.aver_stride_freq = data.step->aver_stride_freq;
            record.step.aver_stride = data.step->aver_stride;
            record.stride_freq_curve.max_freq = data.step->max_stride_freq;
            record.stride_freq_curve.min_freq = data.step->min_stride_freq;
            record.stride_freq_curve.aver_freq = data.step->aver_stride_freq;
            Hal_Mem_Copy(record.stride_freq_curve.freq, data.step->stride_freq,
                         sizeof(uint8_t) * EXERCISE_RECORD_CURVE_NODE_NUM);
            Hal_Mem_Free(data.step);
        }
        if(data.height) {
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_HEIGHT;
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_ALTITUDE_CURVE;
            record.height.climb_height = data.height->climb_height;
            record.height.decline_height = data.height->decline_height;
            record.height.highest_altitude = data.height->max_altitude;
            record.altitude_curve.max_altitude = data.height->max_altitude;
            record.altitude_curve.min_altitude = data.height->min_altitude;
            record.altitude_curve.aver_altitude = data.height->aver_altitude;
            Hal_Mem_Copy(record.altitude_curve.height, data.height->height,
                         sizeof(uint16_t) * EXERCISE_RECORD_CURVE_NODE_NUM);
            Hal_Mem_Free(data.height);
        }
        if(data.vo2max) {
            record.base.bitmap |= 1 << EXERCISE_RECORD_ITEM_TYPE_VO2MAX;
            record.vo2max.value = data.vo2max->vo2max;
            Hal_Mem_Copy(record.vo2max.zone, data.vo2max->zone,
                         sizeof(uint8_t) * EXERCISE_RECORD_VO2MAX_ZONE_NUM + 1);
            Hal_Mem_Free(data.vo2max);
        }
        exercise_record_sport_data_ind(&record);
#else
        if(data.speed) Hal_Mem_Free(data.speed);
        if(data.pace) Hal_Mem_Free(data.pace);
        if(data.step) Hal_Mem_Free(data.step);
        if(data.height) Hal_Mem_Free(data.height);
        if(data.vo2max) Hal_Mem_Free(data.vo2max);
#endif
    } else {
        exercise_test_sport_stop_req(NULL);
    }
#else
#endif
}

static uint8_t exercise_prepare_to_stop_sport(void)
{
#if EXERCISE_TEST_MODE != 0
    return(exercise_test_prepare_to_stop_sport());
#else
    return(0);
#endif
}

static void exercise_volume_slider_cb(lv_obj_t * slider, lv_event_t event)
{
    if(LV_EVENT_RELEASED != event) return;

    uint8_t vol = (uint8_t)lv_slider_get_value(slider);
    uint8_t old_vol = lv_watch_get_free_num(slider);
    if(old_vol == vol) return;

    setting_set_ring_volume(vol, true, false);
    Hal_Audio_SetVolume(vol);
    lv_watch_set_free_num(slider, vol);

    lv_obj_t * bg = lv_obj_get_parent(slider);
    lv_obj_t * cont = lv_obj_get_child_back(bg, NULL);
    lv_obj_t * img = lv_obj_get_child_back(cont, NULL);
    if(0 == vol) {
        lv_img_set_src(img, ICON_EXERCISE_MUTE);
    } else if(0 == old_vol) {
        lv_img_set_src(img, ICON_EXERCISE_VOLUME_MIN);
    } else {
        return;
    }
    lv_img_set_zoom(img,
                    LV_IMG_ZOOM_NONE * lv_obj_get_width(cont) / (lv_obj_get_width(img) * 2));
    lv_obj_align(img, cont, LV_ALIGN_CENTER, 0, 0);
}

static void exercise_volume_create(void)
{
    lv_watch_activity_ext_t activity_ext = {};
    activity_ext.actId = ACT_ID_EXERCISE_VOLUME;
    activity_ext.create = NULL;
    activity_ext.prepare_destory = NULL;
    lv_obj_t * activity_obj = lv_watch_creat_activity_obj(&activity_ext);
    LV_ASSERT_MEM(activity_obj);

    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);

    lv_obj_t * bg = lv_cont_create(obj, NULL);
    lv_obj_set_click(bg, false);
    lv_obj_set_style_local_bg_opa(bg, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(bg, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_obj_set_size(bg, LV_HOR_RES, LV_VER_RES);
    lv_obj_align(bg, obj, LV_ALIGN_CENTER, 0, 0);

    lv_coord_t bg_ver = LV_VER_RES / 40;
    lv_coord_t cont_size = LV_VER_RES / 5;
    lv_obj_t * down_cont = lv_cont_create(bg, NULL);
    lv_obj_set_size(down_cont, cont_size, cont_size);
    lv_obj_set_style_local_bg_opa(down_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_80);
    lv_obj_set_style_local_bg_color(down_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_obj_set_style_local_radius(down_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, cont_size);
    lv_obj_align(down_cont, bg, LV_ALIGN_IN_BOTTOM_MID, 0, -bg_ver);

    lv_obj_t * img = lv_img_create(down_cont, NULL);
    lv_img_set_auto_size(img, true);
    uint8_t vol = setting_get_ring_volume();
    if(0 == vol) {
        lv_img_set_src(img, ICON_EXERCISE_MUTE);
    } else {
        lv_img_set_src(img, ICON_EXERCISE_VOLUME_MIN);
    }
    lv_img_set_zoom
        (img, LV_IMG_ZOOM_NONE * lv_obj_get_width(down_cont) / (lv_obj_get_width(img) * 2));
    lv_obj_align(img, down_cont, LV_ALIGN_CENTER, 0, 0);

    lv_obj_t * up_cont = lv_cont_create(bg, down_cont);
    lv_obj_align(up_cont, bg, LV_ALIGN_IN_TOP_MID, 0, bg_ver);
    img = lv_img_create(up_cont, img);
    lv_img_set_src(img, ICON_EXERCISE_VOLUME_MAX);
    lv_img_set_zoom
        (img, LV_IMG_ZOOM_NONE * lv_obj_get_width(up_cont) / (lv_obj_get_width(img) * 2));
    lv_obj_align(img, up_cont, LV_ALIGN_CENTER, 0, 0);

    lv_coord_t slider_w = 20;
    lv_coord_t slider_h = LV_VER_RES - 2 * cont_size - 3 * bg_ver;
    lv_obj_t * slider_bg = lv_cont_create(bg, NULL);
    lv_obj_set_size(slider_bg, slider_w / 5, slider_h - slider_w);
    lv_obj_set_style_local_radius(slider_bg, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
    lv_obj_set_style_local_bg_opa(slider_bg, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(slider_bg, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_obj_align(slider_bg, bg, LV_ALIGN_CENTER, 0, 0);

    lv_obj_t * slider = lv_slider_create(bg, NULL);
    lv_obj_set_size(slider, slider_w, slider_h);
    lv_slider_set_range(slider, 0, 10); /*refer to setting_volume.c*/
    lv_slider_set_value(slider, vol, LV_ANIM_OFF);
    lv_obj_set_style_local_bg_opa(slider, LV_SLIDER_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
    lv_obj_set_style_local_pad_top(slider, LV_SLIDER_PART_BG, LV_STATE_DEFAULT, slider_w / 2);
    lv_obj_set_style_local_pad_bottom(slider, LV_SLIDER_PART_BG, LV_STATE_DEFAULT, slider_w / 2);
    lv_obj_set_style_local_pad_left(slider, LV_SLIDER_PART_BG, LV_STATE_DEFAULT, slider_w * 2 / 5);
    lv_obj_set_style_local_pad_right(slider, LV_SLIDER_PART_BG, LV_STATE_DEFAULT, slider_w * 2 / 5);
    lv_obj_set_style_local_border_width(slider, LV_SLIDER_PART_BG, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_shadow_width(slider, LV_SLIDER_PART_BG, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_bg_color(slider, LV_SLIDER_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_WHITE);
    lv_obj_set_style_local_bg_opa(slider, LV_SLIDER_PART_INDIC, LV_STATE_DEFAULT, LV_OPA_80);
    lv_obj_set_style_local_radius(slider, LV_SLIDER_PART_INDIC, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
    lv_obj_set_style_local_pad_left(slider, LV_SLIDER_PART_INDIC, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_pad_right(slider, LV_SLIDER_PART_INDIC, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_border_width(slider, LV_SLIDER_PART_INDIC, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_shadow_width(slider, LV_SLIDER_PART_INDIC, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_radius(slider, LV_SLIDER_PART_KNOB, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
    lv_obj_set_style_local_bg_color(slider, LV_SLIDER_PART_KNOB, LV_STATE_DEFAULT, LV_COLOR_WHITE);
    lv_obj_set_style_local_bg_opa(slider, LV_SLIDER_PART_KNOB, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_pad_top(slider, LV_SLIDER_PART_KNOB, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_pad_bottom(slider, LV_SLIDER_PART_KNOB, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_pad_left(slider, LV_SLIDER_PART_KNOB, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_pad_right(slider, LV_SLIDER_PART_KNOB, LV_STATE_DEFAULT, 0);
    lv_obj_set_event_cb(slider, exercise_volume_slider_cb);
    lv_obj_align(slider, bg, LV_ALIGN_CENTER, 0, 0);
    lv_watch_set_free_num(slider, vol);
}

#if EXERCISE_TEST_MODE != 0
static void exercise_get_hr_zone(uint8_t * hr_zone)
{
    exercise_test_get_hr_zone(hr_zone);
}

static void exercise_set_hr_arc_state(lv_obj_t * btn, int32_t hr_value)
{
    exercise_btn_ext_t * ext = lv_obj_get_ext_attr(btn);

    uint16_t txt_id;
    uint8_t cur_hr_value = hr_value;
    uint8_t hr_range;
    uint8_t color_index;
    uint8_t hr_zone[EXERCISE_MAX_HR_ZONE_NUM + 1] = {};
    exercise_get_hr_zone(hr_zone);
    if(hr_zone[1] >= cur_hr_value) {
        hr_range = hr_zone[1] - hr_zone[0];
        if(hr_zone[0] >= cur_hr_value) {
            cur_hr_value = 1;
        } else {
            cur_hr_value -= hr_zone[0];
        }
        txt_id = WATCH_TEXT_ID_WARM_UP;
        color_index = 0;
    } else if(hr_zone[2] >= cur_hr_value) {
        hr_range = hr_zone[2] - hr_zone[1];
        cur_hr_value -= hr_zone[1];
        txt_id = WATCH_TEXT_ID_FAT_BURNING;
        color_index = 1;
    } else if(hr_zone[3] >= cur_hr_value) {
        hr_range = hr_zone[3] - hr_zone[2];
        cur_hr_value -= hr_zone[2];
        txt_id = WATCH_TEXT_ID_AEROBIC_TRAINING;
        color_index = 2;
    } else if(hr_zone[4] >= cur_hr_value) {
        hr_range = hr_zone[4] - hr_zone[3];
        cur_hr_value -= hr_zone[3];
        txt_id = WATCH_TEXT_ID_ANAEROBIC_TRAINING;
        color_index = 3;
    } else {
        hr_range = hr_zone[5] - hr_zone[4];
        if(hr_zone[5] < cur_hr_value) {
            cur_hr_value = hr_range;
        } else {
            cur_hr_value -= hr_zone[4];
        }
        txt_id = WATCH_TEXT_ID_EXTREME;
        color_index = 4;
    }

    if(ext->color_index != color_index) {
        lv_obj_t * arc = lv_obj_get_child_back(btn, NULL);
        uint8_t i = 0;
        while(arc) {
            if(ext->color_index == i) {
                lv_obj_set_style_local_line_opa(arc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_50);
            } else if(color_index == i) {
                lv_obj_set_style_local_line_opa(arc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_COVER);
                if(lv_obj_get_hidden(ext->hr_state_cont)) {
                    lv_obj_set_hidden(ext->hr_state_cont, false);
                }
                lv_obj_set_style_local_bg_color(ext->hr_state_cont, LV_CONT_PART_MAIN,
                                                LV_STATE_DEFAULT,
                                                lv_obj_get_style_line_color(arc, LV_ARC_PART_BG));
                lv_obj_t * label = lv_obj_get_child_back(ext->hr_state_cont, NULL);
                lv_label_set_text_id(label, txt_id);
            }
            i++;
            arc = lv_obj_get_child_back(btn, arc);
        }

        ext->color_index = color_index;
    }

    if(lv_obj_get_hidden(ext->pointer_img)) {
        lv_obj_set_hidden(ext->pointer_img, false);
    }

    int32_t step_angle = EXERCISE_HR_ARC_ANGLE / EXERCISE_MAX_HR_ZONE_NUM;
    int32_t cur_angle;
    if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(btn)) {
        int32_t start_angle = 270 + EXERCISE_HR_ARC_ANGLE / 2;
        int32_t cur_start_angle = start_angle - step_angle * color_index;
        cur_angle = cur_start_angle * 10 -
            (10 * step_angle * cur_hr_value - 5 * step_angle) / hr_range;
    } else {
        int32_t start_angle = 270 - EXERCISE_HR_ARC_ANGLE / 2;
        int32_t cur_start_angle = start_angle + step_angle * color_index;
        cur_angle = cur_start_angle * 10 +
            (10 * step_angle * cur_hr_value - 5 * step_angle) / hr_range;
    }
    lv_img_set_angle(ext->pointer_img, cur_angle);
}

static bool exercise_set_training_effect_arc_state(lv_obj_t * btn, lv_obj_t * label, uint8_t value,
                                                   EXERCISE_START_UI_ITEM_TYPE_T type)
{
    if(10 > value) {
        return(false);
    }

    if((EXERCISE_START_UI_ITEM_TYPE_AEROBIC_TRAINING != type)
       && (EXERCISE_START_UI_ITEM_TYPE_ANAEROBIC_TRAINING != type)) {
        printf("%s: warning, wrong type %d\n", __FUNCTION__, type);
        return(false);
    }

    lv_bidi_dir_t dir = lv_obj_get_base_dir(btn);

    lv_obj_t * arc = lv_obj_get_child_back(btn, NULL);
    if(EXERCISE_START_UI_ITEM_TYPE_ANAEROBIC_TRAINING == type) {
        arc = lv_obj_get_child_back(btn, arc);
    }
    uint8_t last_value = lv_watch_get_free_num(arc);
    if(last_value == value) return(false);

    lv_watch_set_free_num(arc, value);

    if(10 > last_value) {
        lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                          lv_obj_get_style_line_color(arc, LV_ARC_PART_INDIC));
    }
    int32_t angle;
    if(((LV_BIDI_DIR_RTL != dir)
        && (EXERCISE_START_UI_ITEM_TYPE_AEROBIC_TRAINING == type))
       || ((LV_BIDI_DIR_RTL == dir)
           && (EXERCISE_START_UI_ITEM_TYPE_ANAEROBIC_TRAINING == type))) {
        int32_t start_angle = 180 - EXERCISE_TRANING_EFFECT_ARC_ANGLE / 2;
        angle = start_angle + EXERCISE_TRANING_EFFECT_ARC_ANGLE * (value - 9) / 41;
        lv_arc_set_angles(arc, start_angle, angle);
    } else {
        int32_t end_angle = EXERCISE_TRANING_EFFECT_ARC_ANGLE / 2;
        angle = end_angle - EXERCISE_TRANING_EFFECT_ARC_ANGLE * (value - 9) / 41;
        if(0 > angle) {
            angle += 360;
            end_angle += 360;
        }
        lv_arc_set_angles(arc, angle, end_angle);
    }
    if(10 > last_value) {
        lv_obj_t * cont = lv_obj_get_parent(label);
        lv_obj_t * symbol_label = lv_obj_get_child(cont, label);
        if(symbol_label) {
            lv_cont_set_fit(cont, LV_FIT_NONE);
            lv_obj_del(symbol_label);
            lv_obj_align(label, cont, LV_ALIGN_CENTER, 0, 0);
        }
        lv_obj_t * txt_label = lv_obj_get_child(btn, cont);
        lv_obj_set_style_local_text_color(txt_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                          LV_COLOR_WHITE);
    }

    return(true);
}
#endif

static void exercise_sport_start_update_task_cb(lv_task_t * task)
{
#if EXERCISE_TEST_MODE != 0
    lv_obj_t * list = task->user_data;
    exercise_list_ext_t * list_ext = lv_obj_get_ext_attr(list);

    uint8_t i;
    EXERCISE_START_UI_ITEM_TYPE_T item_type;
    exercise_btn_ext_t * ext;
    char str[10];
    hal_rtc_t time;
    Hal_Rtc_Gettime(&time);
    char time_str[6];
    snprintf(time_str, 6, "%02d:%02d", time.tm_hour, time.tm_min);
    uint32_t seconds;
    uint32_t minutes;
    uint32_t hours;
    uint32_t target_pace;
    uint32_t distance;
    lv_obj_t * label;
    exercise_test_sport_data_t sport_data = {};
    exercise_get_sport_data(&sport_data);
    lv_obj_t * btn = lv_list_get_next_btn(list, NULL);
    while(btn) {
        ext = lv_obj_get_ext_attr(btn);

        for(i = 0;i < EXERCISE_MAX_ITEM_NUM_PER_START_UI;i++) {
            if(NULL == ext->label[i]) {
                break;
            }

            item_type = lv_watch_get_free_num(ext->label[i]);
            switch(item_type) {
            case EXERCISE_START_UI_ITEM_TYPE_HEART_RATE:
                if(0 == sport_data.hr_value) continue;
                exercise_int_to_str(sport_data.hr_value, str, 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_PACE:
                seconds = sport_data.pace_value % 60;
                minutes = sport_data.pace_value / 60;
                snprintf(str, 10, "%02d'%02d\"", minutes, seconds);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_DISTANCE:
                if(10 > sport_data.distance_value) continue;
                snprintf(str, 10, "%d.%d%d", sport_data.distance_value / 1000,
                         (sport_data.distance_value / 100) % 10,
                         (sport_data.distance_value / 10) % 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_DURATION:
                seconds = time_to_seconds(&time) - list_ext->start_time;
                minutes = seconds / 60;
                seconds = seconds % 60;
                hours = minutes / 60;
                minutes = minutes % 60;
                snprintf(str, 10, "%02d:%02d:%02d", hours, minutes, seconds);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_STEP_NUMBER:
                exercise_int_to_str(sport_data.step_num_value, str, 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_STRIDE_FREQUENCY:
                exercise_int_to_str(sport_data.stride_freq_value, str, 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_CALORIE:
                exercise_int_to_str(sport_data.calorie_value, str, 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_CUMULATIVELY_CLIMB:
                if(0 == sport_data.climb_value / 10) {
                    snprintf(str, 10, "%d", sport_data.climb_value / 10);
                } else {
                    snprintf(str, 10, "%d.%d", sport_data.climb_value / 10,
                        sport_data.climb_value % 10);
                }
                break;
            case EXERCISE_START_UI_ITEM_TYPE_HEIGHT:
                if(0 == sport_data.climb_value / 10) {
                    snprintf(str, 10, "%d", sport_data.height_value / 10);
                } else {
                    snprintf(str, 10, "%d.%d", sport_data.height_value / 10,
                        sport_data.height_value % 10);
                }
                break;
            case EXERCISE_START_UI_ITEM_TYPE_AEROBIC_TRAINING:
                if(false == exercise_set_training_effect_arc_state(
                       btn, ext->label[i],
                       sport_data.aerobic_training_value,
                       item_type)) {
                    continue;
                }
                snprintf(str, 10, "%d.%d", sport_data.aerobic_training_value / 10,
                         sport_data.aerobic_training_value % 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_ANAEROBIC_TRAINING:
                if(false == exercise_set_training_effect_arc_state(
                       btn, ext->label[i],
                       sport_data.anaerobic_training_value,
                       item_type)) {
                    continue;
                }
                snprintf(str, 10, "%d.%d", sport_data.anaerobic_training_value / 10,
                         sport_data.anaerobic_training_value % 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_SPEED:
                if(10 > sport_data.distance_value) continue;
                snprintf(str, 10, "%d.%d%d", sport_data.speed_value / 1000,
                         (sport_data.speed_value / 100) % 10,
                         (sport_data.speed_value / 10) % 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_AVERAGE_SPEED:
                if(10 > sport_data.distance_value) continue;
                snprintf(str, 10, "%d.%d%d", sport_data.aver_speed_value / 1000,
                         (sport_data.aver_speed_value / 100) % 10,
                         (sport_data.aver_speed_value / 10) % 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_RELATIVE_DISTANCE:
                target_pace = lv_watch_get_free_num(btn);
                distance = 1000 * sport_data.duration / target_pace;
                label = lv_obj_get_child(btn, ext->label[i]);
                if(sport_data.distance_value <= distance) {
                    if(WATCH_TEXT_ID_BEHIND_DISTANCE != label->user_data.user_num) {
                        lv_label_set_text_id(label, WATCH_TEXT_ID_BEHIND_DISTANCE);
                    }
                    distance -= sport_data.distance_value;
                } else {
                    if(WATCH_TEXT_ID_BEYOND_DISTANCE != label->user_data.user_num) {
                        lv_label_set_text_id(label, WATCH_TEXT_ID_BEYOND_DISTANCE);
                    }
                    distance = sport_data.distance_value - distance;
                }
                snprintf(str, 10, "%d.%d%d", distance / 1000, (distance / 100) % 10,
                         (distance / 10) % 10);
                break;
            case EXERCISE_START_UI_ITEM_TYPE_AVERAGE_PACE:
                seconds = sport_data.aver_pace_value % 60;
                minutes = sport_data.aver_pace_value / 60;
                snprintf(str, 10, "%d'%02d\"", minutes, seconds);
                break;
            default:
                printf("%s: warning, invalid item type %d\n", __FUNCTION__, item_type);
                break;
            }
            lv_label_set_text(ext->label[i], str);
        }

        if((EXERCISE_ARC_TYPE_HR == ext->arc_type) && (0 < sport_data.hr_value)) {
            exercise_set_hr_arc_state(btn, sport_data.hr_value);
        }

        if(ext->time_label) {
            lv_label_set_text(ext->time_label, time_str);
        }

        btn = lv_list_get_next_btn(list, btn);
    }
#endif
}

static void exercise_sport_start_lock_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_EXERCISE_SPORT);
    lv_obj_t * tileview = lv_obj_get_child_back(activity_obj, NULL);
    exercise_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);
    lv_obj_t * img = lv_obj_get_child_back(btn, NULL);
    if(false == ext->is_wakey) {
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_WHITE);
        lv_img_set_src(img, ICON_EXERCISE_LOCK);
        lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * lv_obj_get_height(btn) / lv_obj_get_height(img));
        watch_set_suspend_enable(false, ACT_ID_EXERCISE_SPORT, false);
        ext->is_wakey = true;
    } else {
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_MAKE(0x53, 0x5C, 0x60));
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED,
                                        LV_COLOR_MAKE(0x53, 0x5C, 0x60));
        lv_img_set_src(img, ICON_EXERCISE_UNLOCK);
        lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * lv_obj_get_height(btn) / lv_obj_get_height(img));
        lv_watch_set_free_num(btn, 0);
        watch_set_suspend_enable(true, ACT_ID_EXERCISE_SPORT, false);
        ext->is_wakey = false;
    }
    lv_obj_align(img, btn, LV_ALIGN_CENTER, 0, 0);
}

static void exercise_sport_start_volume_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    exercise_volume_create();
}

static void exercise_sport_start_continue_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_EXERCISE_SPORT);
    lv_obj_t * tileview = lv_obj_get_child_back(activity_obj, NULL);
    exercise_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);
    lv_obj_del(ext->pause_cont);
    ext->pause_cont = NULL;
}

static void exercise_sport_start_stop_cancel_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_EXERCISE_SPORT);
    lv_obj_t * tileview = lv_obj_get_child_back(activity_obj, NULL);
    exercise_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);
    lv_obj_del(ext->stop_cont);
    ext->stop_cont = NULL;
}

static void exercise_sport_start_stop_ok_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    exercise_del_ui(ACT_ID_EXERCISE_SPORT);
}

static void exercise_sport_start_stop_cb(lv_obj_t * obj, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_EXERCISE_SPORT);
    lv_obj_t * tileview = lv_obj_get_child_back(activity_obj, NULL);
    exercise_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);

    lv_obj_t * par = lv_obj_get_parent(obj);
    lv_obj_t * cont = lv_cont_create(par, NULL);
    lv_obj_set_size(cont, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_opa(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_obj_align(cont, par, LV_ALIGN_CENTER, 0, 0);
    ext->stop_cont = cont;

    lv_obj_t * label = lv_label_create(cont, NULL);
    lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_NORMAL);
    lv_obj_set_style_local_text_letter_space(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
    lv_obj_set_width(label, lv_obj_get_width(cont) * 3 / 4);
    uint8_t is_sport_data_valid = 0;
    if(exercise_prepare_to_stop_sport()) {
        lv_label_set_text_id(label, WATCH_TEXT_ID_OVER_Q);
        is_sport_data_valid = 1;
    } else {
        lv_label_set_text_id(label, WATCH_TEXT_ID_OVER_WITHNOT_RECORD_DATA_Q);
    }
    lv_coord_t cont_h = lv_obj_get_height(cont);
    lv_obj_align(label, cont, LV_ALIGN_IN_TOP_MID, 0, cont_h / 6);

    lv_bidi_dir_t dir = lv_obj_get_base_dir(cont);

    lv_obj_t * btn = lv_btn_create(cont, NULL);
    lv_coord_t btn_size = LV_VER_RES / 5;
    lv_obj_set_size(btn, btn_size, btn_size);
    lv_obj_set_style_local_bg_opa(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50);
    lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_obj_set_style_local_radius(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, btn_size);
    lv_coord_t label_y2 = lv_obj_get_y(label) + lv_obj_get_height(label);
    lv_coord_t inner = cont_h / 20;
    if(LV_BIDI_DIR_RTL == dir) {
        if((cont_h - label_y2 - inner) >= 2 * btn_size) {
            lv_obj_align(btn, cont, LV_ALIGN_IN_BOTTOM_RIGHT, -btn_size, -btn_size);
        } else {
            lv_obj_align(btn, cont, LV_ALIGN_IN_TOP_RIGHT, -btn_size, label_y2 + inner);
        }
    } else {
        if((cont_h - label_y2 - inner) >= 2 * btn_size) {
            lv_obj_align(btn, cont, LV_ALIGN_IN_BOTTOM_LEFT, btn_size, -btn_size);
        } else {
            lv_obj_align(btn, cont, LV_ALIGN_IN_TOP_LEFT, btn_size, label_y2 + inner);
        }
    }
    lv_obj_set_event_cb(btn, exercise_sport_start_stop_cancel_cb);

    label = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_BIG);
    lv_obj_set_style_local_text_letter_space(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
    lv_label_set_text(label, LV_SYMBOL_CLOSE);
    lv_obj_align(label, btn, LV_ALIGN_CENTER, 0, 0);

    lv_obj_t * btn_right = lv_btn_create(cont, btn);
    lv_obj_set_style_local_bg_opa(btn_right, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(btn_right, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(btn_right, cont, LV_ALIGN_IN_TOP_LEFT, btn_size, lv_obj_get_y(btn));
    } else {
        lv_obj_align(btn_right, cont, LV_ALIGN_IN_TOP_RIGHT, -btn_size, lv_obj_get_y(btn));
    }
    lv_obj_set_event_cb(btn_right, exercise_sport_start_stop_ok_cb);
    lv_watch_set_free_num(btn_right, is_sport_data_valid);

    label = lv_label_create(btn_right, label);
    lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
    lv_label_set_text(label, LV_SYMBOL_OK);
    lv_obj_align(label, btn_right, LV_ALIGN_CENTER, 0, 0);
}

static void exercise_sport_start_up_func_key_cb(lv_obj_t * activity_obj)
{
    if(NULL == activity_obj) {
        printf("%s: warning, activity_obj is NULL\n", __FUNCTION__);
        return;
    }

    printf("%s\n", __FUNCTION__);

    lv_obj_t * tileview = lv_obj_get_child_back(activity_obj, NULL);
    exercise_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);
    if(ext->pause_cont) {
        if(lv_watch_get_activity_obj(ACT_ID_EXERCISE_VOLUME)) {
            exercise_del_ui(ACT_ID_EXERCISE_VOLUME);
        } else if(ext->stop_cont) {
            lv_obj_del(ext->stop_cont);
            ext->stop_cont = NULL;
        } else {
            lv_obj_del(ext->pause_cont);
            ext->pause_cont = NULL;
        }
    } else {
        lv_obj_t * cont = lv_cont_create(activity_obj, NULL);
        lv_obj_set_size(cont, LV_HOR_RES, LV_VER_RES);
        lv_obj_set_style_local_bg_opa(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_80);
        lv_obj_set_style_local_bg_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
        lv_obj_align(cont, activity_obj, LV_ALIGN_CENTER, 0, 0);
        ext->pause_cont = cont;

        lv_obj_t * label = lv_label_create(cont, NULL);
        lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                         LV_THEME_WATCH_NIGHT_FONT_NORMAL);
        lv_obj_set_style_local_text_letter_space(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
        lv_label_set_text_id(label, WATCH_TEXT_ID_PAUSED);
        lv_obj_align(label, cont, LV_ALIGN_CENTER, 0, 0);

        lv_bidi_dir_t dir = lv_obj_get_base_dir(cont);

        lv_coord_t btn_size = LV_VER_RES / 5;
        lv_obj_t * btn = lv_btn_create(cont, NULL);
        if(ext->is_wakey) {
            lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
            lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_WHITE);
        } else {
            lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT,
                                            LV_COLOR_MAKE(0x53, 0x5C, 0x60));
            lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED,
                                            LV_COLOR_MAKE(0x53, 0x5C, 0x60));
        }
        lv_obj_set_style_local_radius(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
        lv_btn_set_fit(btn, LV_FIT_NONE);
        lv_obj_set_size(btn, btn_size, btn_size);
        if(LV_BIDI_DIR_RTL == dir) {
            lv_obj_align(btn, cont, LV_ALIGN_IN_TOP_RIGHT, -btn_size, btn_size);
        } else {
            lv_obj_align(btn, cont, LV_ALIGN_IN_TOP_LEFT, btn_size, btn_size);
        }
        lv_obj_set_event_cb(btn, exercise_sport_start_lock_cb);

        lv_obj_t * img = lv_img_create(btn, NULL);
        if(ext->is_wakey) {
            lv_img_set_src(img, ICON_EXERCISE_LOCK);
        } else {
            lv_img_set_src(img, ICON_EXERCISE_UNLOCK);
        }
        lv_obj_align(img, btn, LV_ALIGN_CENTER, 0, 0);
        lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * btn_size / lv_obj_get_height(img));

        btn = lv_btn_create(cont, btn);
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_WHITE);
        if(LV_BIDI_DIR_RTL == dir) {
            lv_obj_align(btn, cont, LV_ALIGN_IN_TOP_LEFT, btn_size, btn_size);
        } else {
            lv_obj_align(btn, cont, LV_ALIGN_IN_TOP_RIGHT, -btn_size, btn_size);
        }
        lv_obj_set_event_cb(btn, exercise_sport_start_volume_cb);

        img = lv_img_create(btn, NULL);
        lv_img_set_src(img, ICON_EXERCISE_VOLUME);
        lv_obj_align(img, btn, LV_ALIGN_CENTER, 0, 0);
        lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * btn_size / lv_obj_get_height(img));

        btn = lv_btn_create(cont, btn);
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_MAKE(0x00, 0xB5, 0x01));
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED,
                                        LV_COLOR_MAKE(0x00, 0xB5, 0x01));
        if(LV_BIDI_DIR_RTL == dir) {
            lv_obj_align(btn, cont, LV_ALIGN_IN_BOTTOM_RIGHT, -btn_size, -btn_size);
        } else {
            lv_obj_align(btn, cont, LV_ALIGN_IN_BOTTOM_LEFT, btn_size, -btn_size);
        }
        lv_obj_set_event_cb(btn, exercise_sport_start_continue_cb);

        img = lv_img_create(btn, NULL);
        lv_img_set_src(img, ICON_EXERCISE_START);
        lv_obj_align(img, btn, LV_ALIGN_CENTER, 0, 0);
        lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * btn_size / lv_obj_get_height(img));

        btn = lv_btn_create(cont, btn);
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_MAKE(0xFF, 0x42, 0x31));
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED,
                                        LV_COLOR_MAKE(0xFF, 0x42, 0x31));
        if(LV_BIDI_DIR_RTL == dir) {
            lv_obj_align(btn, cont, LV_ALIGN_IN_BOTTOM_LEFT, btn_size, -btn_size);
        } else {
            lv_obj_align(btn, cont, LV_ALIGN_IN_BOTTOM_RIGHT, -btn_size, -btn_size);
        }
        lv_obj_set_event_cb(btn, exercise_sport_start_stop_cb);

        img = lv_img_create(btn, NULL);
        lv_img_set_src(img, ICON_EXERCISE_STOP);
        lv_obj_align(img, btn, LV_ALIGN_CENTER, 0, 0);
        lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * btn_size / lv_obj_get_height(img));
    }
}

static void exercise_sport_start_down_func_key_cb(lv_obj_t * activity_obj)
{
    if(NULL == activity_obj) {
        printf("%s: warning, activity_obj is NULL\n", __FUNCTION__);
        return;
    }

    // focus the next btn
    lv_obj_t * tileview = lv_obj_get_child_back(activity_obj, NULL);
    exercise_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);
    if(0 != ext->old_ext.act_id.x) return;

    lv_obj_t * list = lv_obj_get_child_back(lv_obj_get_child(tileview, NULL), NULL);
    lv_obj_t * focus_btn = lv_list_get_btn_selected(list);
    lv_obj_t * btn = lv_list_get_next_btn(list, focus_btn);
    if(NULL == btn) return;

    if((1 < lv_list_get_size(list)) && (NULL == lv_list_get_next_btn(list, btn))) {
        uint16_t anim_time = lv_list_get_anim_time(list);
        lv_list_set_anim_time(list, 0);
        lv_obj_t * scrl = lv_page_get_scrollable(list);
        _lv_ll_move_before(&scrl->child_ll, lv_obj_get_child_back(scrl, NULL), btn);
        scrl->signal_cb(scrl, LV_SIGNAL_CHILD_CHG, NULL);
        lv_list_focus_btn(list, focus_btn);
        lv_list_set_anim_time(list, anim_time);
    }

    lv_list_focus_btn(list, btn);
}

static void exercise_sport_set_item_type_and_def_value(lv_obj_t * label,
                                                       EXERCISE_START_UI_ITEM_TYPE_T item_type)
{
    lv_watch_set_free_num(label, item_type);

    switch(item_type) {
    case EXERCISE_START_UI_ITEM_TYPE_HEART_RATE:
        lv_label_set_text(label, "--");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_PACE:
        lv_obj_set_base_dir(label, LV_BIDI_DIR_LTR);
        lv_label_set_text(label, "--'--\"");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_DISTANCE:
        lv_label_set_text(label, "0.00");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_DURATION:
        lv_obj_set_base_dir(label, LV_BIDI_DIR_LTR);
        lv_label_set_text(label, "00:00:00");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_STEP_NUMBER:
    case EXERCISE_START_UI_ITEM_TYPE_STRIDE_FREQUENCY:
    case EXERCISE_START_UI_ITEM_TYPE_CALORIE:
    case EXERCISE_START_UI_ITEM_TYPE_CUMULATIVELY_CLIMB:
    case EXERCISE_START_UI_ITEM_TYPE_HEIGHT:
        lv_label_set_text(label, "0");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_AEROBIC_TRAINING:
    case EXERCISE_START_UI_ITEM_TYPE_ANAEROBIC_TRAINING:
        lv_label_set_text(label, "1.0");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_SPEED:
    case EXERCISE_START_UI_ITEM_TYPE_AVERAGE_SPEED:
        lv_label_set_text(label, "0.00");
        break;
    default:
        printf("%s: warning, invalid type %d\n", __FUNCTION__, item_type);
        break;
    }
}

static void exercise_sport_set_item_txt(lv_obj_t * label,
                                        EXERCISE_START_UI_ITEM_TYPE_T item_type)
{
    switch(item_type) {
    case EXERCISE_START_UI_ITEM_TYPE_HEART_RATE:
        lv_label_set_text_id(label, WATCH_TEXT_ID_HEART_RATE);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(bpm)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_PACE:
        lv_label_set_text_id(label, WATCH_TEXT_ID_PACE);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(/km)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_DISTANCE:
        lv_label_set_text_id(label, WATCH_TEXT_ID_DISTANCE);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(km)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_DURATION:
        lv_label_set_text(label, "00:00:00");
        lv_label_set_text_id(label, WATCH_TEXT_ID_TIME);
        break;
    case EXERCISE_START_UI_ITEM_TYPE_STEP_NUMBER:
        lv_label_set_text_id(label, WATCH_TEXT_ID_STEP_NUMBER);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(steps)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_STRIDE_FREQUENCY:
        lv_label_set_text_id(label, WATCH_TEXT_ID_STRIDE_FREQUENCY);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(/min)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_CALORIE:
        lv_label_set_text_id(label, WATCH_TEXT_ID_CALORIE);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(kcal)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_CUMULATIVELY_CLIMB:
        lv_label_set_text_id(label, WATCH_TEXT_ID_CUMULATIVELY_CLIMB);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(m)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_HEIGHT:
        lv_label_set_text_id(label, WATCH_TEXT_ID_HEIGHT);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(m)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_AEROBIC_TRAINING:
        lv_label_set_text_id(label, WATCH_TEXT_ID_AEROBIC_TRAINING);
        break;
    case EXERCISE_START_UI_ITEM_TYPE_ANAEROBIC_TRAINING:
        lv_label_set_text_id(label, WATCH_TEXT_ID_ANAEROBIC_TRAINING);
        break;
    case EXERCISE_START_UI_ITEM_TYPE_SPEED:
        lv_label_set_text_id(label, WATCH_TEXT_ID_SPEED);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(km/h)");
        break;
    case EXERCISE_START_UI_ITEM_TYPE_AVERAGE_SPEED:
        lv_label_set_text_id(label, WATCH_TEXT_ID_AVER_SPEED);
        lv_label_ins_text(label, LV_LABEL_POS_LAST, "(km/h)");
        break;
    default:
        printf("%s: warning, invalid type %d\n", __FUNCTION__, item_type);
        break;
    }
}

static void exercise_sport_ui_set_4_items_with_time(lv_obj_t * btn, lv_coord_t arc_w,
                                                    exercise_start_ui_desc_t * desc,
                                                    lv_obj_t * hr_state_cont)
{
    exercise_btn_ext_t * ext = lv_obj_get_ext_attr(btn);

    lv_font_t * content_font = LV_THEME_WATCH_NIGHT_FONT_BIG;
    lv_font_t * txt_font = LV_THEME_WATCH_NIGHT_FONT_SMALL;
    lv_font_t * space_font = LV_THEME_WATCH_NIGHT_FONT_NORMAL;
    lv_coord_t font_h = lv_font_get_line_height(space_font);
    if(hr_state_cont) {
        lv_coord_t total_h = LV_VER_RES -
            2 * (lv_obj_get_y(hr_state_cont) + lv_obj_get_height(hr_state_cont));
        lv_coord_t txt_font_h = lv_font_get_line_height(txt_font);
        lv_coord_t content_font_h = lv_font_get_line_height(content_font);
        if(total_h < 3 * (txt_font_h + content_font_h)) {
            printf("%s: ajust font for small space\n", __FUNCTION__);
            content_font = LV_THEME_WATCH_NIGHT_FONT_SMALL;
            space_font = LV_THEME_WATCH_NIGHT_FONT_SMALL;
            font_h = lv_font_get_line_height(space_font);
        }
    }
    lv_coord_t offset_from_center_label = -font_h / 3;

    lv_obj_t * center_label = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(center_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     content_font);
    lv_obj_set_style_local_text_color(center_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                      LV_COLOR_GRAY);
    lv_label_set_text(center_label, "|");
    lv_obj_align(center_label, btn, LV_ALIGN_CENTER, 0, 0);

    uint8_t i = 0;

    lv_bidi_dir_t dir = lv_obj_get_base_dir(btn);

    lv_obj_t * label = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, txt_font);
    lv_obj_set_style_local_text_letter_space(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label, LV_HOR_RES - 2 * arc_w);
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, center_label, LV_ALIGN_OUT_TOP_MID, 0, offset_from_center_label);

    ext->label[i] = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_letter_space(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_font(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     content_font);
    lv_obj_set_style_local_text_color(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                      LV_COLOR_WHITE);
    lv_label_set_align(ext->label[i], LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(ext->label[i], LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(ext->label[i], LV_HOR_RES - 2 * arc_w);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    lv_obj_align(ext->label[i], label, LV_ALIGN_OUT_TOP_MID, 0, 0);
    i++;

    ext->label[i] = lv_label_create(btn, ext->label[i - 1]);
    lv_obj_set_width(ext->label[i],
                     (LV_HOR_RES - lv_obj_get_width(center_label)) / 2 - arc_w * 2);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(ext->label[i], btn, LV_ALIGN_IN_RIGHT_MID, -arc_w * 3 / 2,
                     offset_from_center_label);
    } else {
        lv_obj_align(ext->label[i], btn, LV_ALIGN_IN_LEFT_MID, arc_w * 3 / 2,
                     offset_from_center_label);
    }

    label = lv_label_create(btn, label);
    lv_obj_set_width(label, lv_obj_get_width(ext->label[i]));
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, ext->label[i], LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
    i++;

    ext->label[i] = lv_label_create(btn, ext->label[i - 1]);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(ext->label[i], btn, LV_ALIGN_IN_LEFT_MID, arc_w * 3 / 2,
                     offset_from_center_label);
    } else {
        lv_obj_align(ext->label[i], btn, LV_ALIGN_IN_RIGHT_MID, -arc_w * 3 / 2,
                     offset_from_center_label);
    }

    label = lv_label_create(btn, label);
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, ext->label[i], LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
    i++;

    ext->label[i] = lv_label_create(btn, ext->label[0]);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    lv_obj_align(ext->label[i], center_label, LV_ALIGN_OUT_BOTTOM_MID, 0,
                 lv_obj_get_height(label) + offset_from_center_label);

    label = lv_label_create(btn, label);
    lv_obj_set_width(label, LV_HOR_RES - 2 * arc_w);
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, ext->label[i], LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
}

static void exercise_sport_ui_set_3_items_with_time(lv_obj_t * btn, lv_coord_t arc_w,
                                                    exercise_start_ui_desc_t * desc)
{
    exercise_btn_ext_t * ext = lv_obj_get_ext_attr(btn);

    lv_coord_t font_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_NORMAL);
    lv_coord_t offset_from_center = font_h / 2;

    lv_bidi_dir_t dir = lv_obj_get_base_dir(btn);

    uint8_t i = 0;

    lv_obj_t * label = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_obj_set_style_local_text_letter_space(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label, LV_HOR_RES - 2 * arc_w);
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, btn, LV_ALIGN_CENTER, 0,
                 -lv_obj_get_height(label) / 2 - offset_from_center);

    ext->label[i] = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_letter_space(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_font(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_BIG);
    lv_obj_set_style_local_text_color(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                      LV_COLOR_WHITE);
    lv_label_set_align(ext->label[i], LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(ext->label[i], LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(ext->label[i], LV_HOR_RES - 2 * arc_w);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    lv_obj_align(ext->label[i], label, LV_ALIGN_OUT_TOP_MID, 0, 0);
    i++;

    ext->label[i] = lv_label_create(btn, ext->label[i - 1]);
    lv_obj_set_width(ext->label[i], LV_HOR_RES / 2 - arc_w * 5 / 2);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(ext->label[i], btn, LV_ALIGN_IN_RIGHT_MID, -arc_w * 2, offset_from_center);
    } else {
        lv_obj_align(ext->label[i], btn, LV_ALIGN_IN_LEFT_MID, arc_w * 2, offset_from_center);
    }

    label = lv_label_create(btn, label);
    lv_obj_set_width(label, lv_obj_get_width(ext->label[i]));
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, ext->label[i], LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
    i++;

    ext->label[i] = lv_label_create(btn, ext->label[i - 1]);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(ext->label[i], btn, LV_ALIGN_IN_LEFT_MID, arc_w * 2, offset_from_center);
    } else {
        lv_obj_align(ext->label[i], btn, LV_ALIGN_IN_RIGHT_MID, -arc_w * 2, offset_from_center);
    }

    label = lv_label_create(btn, label);
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, ext->label[i], LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
}

static void exercise_sport_ui_set_2_items_with_time(lv_obj_t * btn, lv_coord_t arc_w,
                                                    exercise_start_ui_desc_t * desc)
{
    exercise_btn_ext_t * ext = lv_obj_get_ext_attr(btn);

    lv_coord_t font_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_NORMAL);
    lv_coord_t offset_from_center = font_h / 2;

    uint8_t i = 0;

    lv_obj_t * label = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_obj_set_style_local_text_letter_space(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label, LV_HOR_RES - 2 * arc_w);
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, btn, LV_ALIGN_CENTER, 0,
                 -lv_obj_get_height(label) / 2 - offset_from_center);

    ext->label[i] = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_letter_space(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_font(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_BIG);
    lv_obj_set_style_local_text_color(ext->label[i], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                      LV_COLOR_WHITE);
    lv_label_set_align(ext->label[i], LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(ext->label[i], LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(ext->label[i], LV_HOR_RES - 2 * arc_w);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    lv_obj_align(ext->label[i], label, LV_ALIGN_OUT_TOP_MID, 0, 0);
    i++;

    ext->label[i] = lv_label_create(btn, ext->label[i - 1]);
    exercise_sport_set_item_type_and_def_value(ext->label[i], desc->item_type[i]);
    lv_obj_align(ext->label[i], btn, LV_ALIGN_CENTER, 0, offset_from_center);

    label = lv_label_create(btn, label);
    exercise_sport_set_item_txt(label, desc->item_type[i]);
    lv_obj_align(label, ext->label[i], LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
}

static void exercise_sport_ui_set_1_item_with_time(lv_obj_t * btn, lv_coord_t arc_w,
                                                   exercise_start_ui_desc_t * desc)
{
    exercise_btn_ext_t * ext = lv_obj_get_ext_attr(btn);

    ext->label[0] = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_letter_space(ext->label[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_font(ext->label[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_BIG);
    lv_obj_set_style_local_text_color(ext->label[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                      LV_COLOR_WHITE);
    lv_label_set_align(ext->label[0], LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(ext->label[0], LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(ext->label[0], LV_HOR_RES - 2 * arc_w);
    exercise_sport_set_item_type_and_def_value(ext->label[0], desc->item_type[0]);
    lv_obj_align(ext->label[0], btn, LV_ALIGN_CENTER, 0,
                 -lv_obj_get_height(ext->label[0]) / 2);

    lv_obj_t * label = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_NORMAL);
    lv_obj_set_style_local_text_letter_space(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
    lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label, LV_HOR_RES - 2 * arc_w);
    lv_coord_t font_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_NORMAL);
    exercise_sport_set_item_txt(label, desc->item_type[0]);
    lv_obj_align(label, ext->label[0], LV_ALIGN_OUT_BOTTOM_MID, 0, font_h / 2);
}

static void exercise_sport_line_event_cb(lv_obj_t * line, lv_event_t event)
{
    if(LV_EVENT_DELETE != event) return;

    Hal_Mem_Free(lv_watch_get_free_ptr(line));
}

static void exercise_sport_ui_set_running_with_ai(lv_obj_t * btn, uint32_t target_pace_value)
{
    exercise_btn_ext_t * ext = lv_obj_get_ext_attr(btn);

    lv_watch_set_free_num(btn, target_pace_value);

    lv_btn_set_layout(btn, LV_LAYOUT_OFF);

    lv_coord_t btn_w = lv_obj_get_width(btn);
    lv_coord_t btn_h = lv_obj_get_height(btn);
    lv_font_t * small_font = LV_THEME_WATCH_NIGHT_FONT_SMALL;
    lv_font_t * big_font = LV_THEME_WATCH_NIGHT_FONT_BIG;
    lv_coord_t small_font_h = lv_font_get_line_height(small_font);
    lv_coord_t big_font_h = lv_font_get_line_height(big_font);
    lv_coord_t small_label_y_offset = (big_font_h - small_font_h) / 2 * small_font_h / big_font_h;
    lv_coord_t area_h = small_font_h + big_font_h;
    lv_coord_t inner = (btn_h / 3 - area_h) / 4;

    lv_bidi_dir_t dir = lv_obj_get_base_dir(btn);

    gif_info_t * info = gif_open(btn, ANIM_EXERCISE, 0);
    lv_obj_add_style(info->container, LV_OBJ_PART_MAIN, &lv_style_transp_tight);
    lv_coord_t zoom_h = btn_h / 3;
    lv_coord_t gif_h = lv_obj_get_height(info->img1);
    lv_coord_t gif_w = lv_obj_get_width(info->img1);
    lv_obj_set_size(info->container, zoom_h * gif_w / gif_h, zoom_h);
    lv_img_set_zoom(info->img1, LV_IMG_ZOOM_NONE * zoom_h / gif_h);
    lv_obj_align(info->img1, info->container, LV_ALIGN_CENTER, 0, 0);
    info->x = lv_obj_get_x(info->img1);
    info->y = lv_obj_get_y(info->img1);
    lv_obj_align(info->container, btn, LV_ALIGN_CENTER, lv_obj_get_width(info->container) / 3, 0);
    ext->info = info;

    lv_obj_t * img = lv_img_create(btn, NULL);
    lv_img_set_src(img, ICON_EXERCISE_STAND);
    lv_coord_t img_h = lv_obj_get_height(img);
    lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * zoom_h / img_h);
    lv_obj_align(img, btn, LV_ALIGN_CENTER, -zoom_h * lv_obj_get_width(img) / (img_h * 2), 0);

    lv_obj_t * line = lv_line_create(btn, NULL);
    lv_obj_set_style_local_line_opa(line, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_line_color(line, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_coord_t line_w = 1;
    lv_obj_set_style_local_line_width(line, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, line_w);
    lv_point_t * line_points = Hal_Mem_Alloc(sizeof(lv_point_t) * 2);
    if(LV_BIDI_DIR_RTL == dir) {
        line_points[0].x = btn_w * 2 / 5 - line_w;
    } else {
        line_points[0].x = btn_w * 3 / 5;
    }
    line_points[0].y = inner * 3 + small_label_y_offset;
    line_points[1].x = line_points[0].x;
    line_points[1].y = line_points[0].y + area_h - 2 * small_label_y_offset;
    lv_line_set_points(line, line_points, 2);
    lv_watch_set_free_ptr(line, line_points);
    lv_obj_set_event_cb(line, exercise_sport_line_event_cb);
    lv_obj_set_x(line, 0);

    lv_obj_t * label_km = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(label_km, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, small_font);
    lv_obj_set_style_local_text_letter_space(label_km, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_label_set_text_id(label_km, WATCH_TEXT_ID_KILOMETRE);
    lv_coord_t hor = btn_w / 40;
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(label_km, btn, LV_ALIGN_IN_BOTTOM_LEFT, btn_w * 2 / 5 + hor,
                     -btn_h * 2 / 3 - inner - small_label_y_offset);
    } else {
        lv_obj_align(label_km, btn, LV_ALIGN_IN_BOTTOM_RIGHT, -btn_w * 2 / 5 - hor,
                     -btn_h * 2 / 3 - inner - small_label_y_offset);
    }

    lv_obj_t * label = lv_label_create(btn, label_km);
    lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label, btn_w * 3 / 8 - hor);
    lv_label_set_text_id(label, WATCH_TEXT_ID_BEHIND_DISTANCE);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_label_set_align(label, LV_LABEL_ALIGN_LEFT);
        lv_obj_align(label, btn, LV_ALIGN_IN_TOP_RIGHT, -btn_w * 3 / 14 + hor, inner * 3);
    } else {
        lv_label_set_align(label, LV_LABEL_ALIGN_RIGHT);
        lv_obj_align(label, btn, LV_ALIGN_IN_TOP_LEFT, btn_w * 3 / 14 - hor, inner * 3);
    }

    ext->label[0] = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(ext->label[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, big_font);
    lv_obj_set_style_local_text_letter_space(ext->label[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_label_set_long_mode(ext->label[0], LV_LABEL_LONG_SROLL_CIRC);
    lv_coord_t distance_w = btn_w / 3;
    lv_obj_set_width(ext->label[0], distance_w);
    lv_label_set_text(ext->label[0], "0.00");
    lv_coord_t space_between_txts = 2;
    if(LV_BIDI_DIR_RTL == dir) {
        lv_label_set_align(ext->label[0], LV_LABEL_ALIGN_LEFT);
        lv_obj_align(ext->label[0], label_km, LV_ALIGN_OUT_BOTTOM_RIGHT,
                     distance_w + space_between_txts, small_label_y_offset - big_font_h);
    } else {
        lv_label_set_align(ext->label[0], LV_LABEL_ALIGN_RIGHT);
        lv_obj_align(ext->label[0], label_km, LV_ALIGN_OUT_BOTTOM_LEFT,
                     -distance_w - space_between_txts, small_label_y_offset - big_font_h);
    }
    lv_watch_set_free_num(ext->label[0], EXERCISE_START_UI_ITEM_TYPE_RELATIVE_DISTANCE);

    ext->label[1] = lv_label_create(btn, ext->label[0]);
    lv_label_set_align(ext->label[1], LV_LABEL_ALIGN_CENTER);
    lv_coord_t txt_w = _lv_txt_get_width("000", 3, big_font, 0, LV_TXT_FLAG_NONE);
    lv_obj_set_width(ext->label[1], txt_w + 2 * hor);
    lv_label_set_text(ext->label[1], "--");
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(ext->label[1], btn, LV_ALIGN_IN_TOP_RIGHT, - btn_w + line_points[0].x,
                     lv_obj_get_y(ext->label[0]));
    } else {
        lv_obj_align(ext->label[1], btn, LV_ALIGN_IN_TOP_LEFT, line_points[0].x + line_w,
                     lv_obj_get_y(ext->label[0]));
    }
    lv_watch_set_free_num(ext->label[1], EXERCISE_START_UI_ITEM_TYPE_HEART_RATE);

    img = lv_img_create(btn, NULL);
    lv_img_set_src(img, ICON_HEART_RATE_HEART);
    img_h = lv_obj_get_height(img);
    lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * small_font_h / img_h);
    lv_obj_align(img, ext->label[1], LV_ALIGN_OUT_TOP_MID, 0, (img_h - small_font_h) / 2);

    label = lv_label_create(btn, label);
    lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
    lv_obj_set_width(label, btn_w * 2 / 3);
    lv_label_set_text_id(label, WATCH_TEXT_ID_AVERAGE_PACE);
    lv_obj_align(label, btn, LV_ALIGN_IN_TOP_MID, 0, btn_h * 2 / 3 + inner);

    lv_coord_t left_txt_w = _lv_txt_get_width("00'00\"", 6, big_font, 0, LV_TXT_FLAG_NONE);
    char * txt = (char *)lv_lang_get_text(WATCH_TEXT_ID_PER_KM);
    txt_w = space_between_txts + left_txt_w +
        _lv_txt_get_width(txt, strlen(txt), small_font, 0, LV_TXT_FLAG_NONE);

    ext->label[2] = lv_label_create(btn, ext->label[1]);
    lv_obj_set_width(ext->label[2], left_txt_w);
    lv_label_set_text(ext->label[2], "-'--\"");
    if(LV_BIDI_DIR_RTL == dir) {
        lv_label_set_align(ext->label[2], LV_LABEL_ALIGN_LEFT);
        lv_obj_align(ext->label[2], btn, LV_ALIGN_IN_TOP_RIGHT, -(btn_w - txt_w) / 2,
                     lv_obj_get_y(label) + lv_obj_get_height(label));
    } else {
        lv_label_set_align(ext->label[2], LV_LABEL_ALIGN_RIGHT);
        lv_obj_align(ext->label[2], btn, LV_ALIGN_IN_TOP_LEFT, (btn_w - txt_w) / 2,
                     lv_obj_get_y(label) + lv_obj_get_height(label));
    }
    lv_watch_set_free_num(ext->label[2], EXERCISE_START_UI_ITEM_TYPE_AVERAGE_PACE);

    label = lv_label_create(btn, label_km);
    lv_label_set_text_id(label, WATCH_TEXT_ID_PER_KM);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(label, ext->label[2], LV_ALIGN_OUT_BOTTOM_RIGHT,
                     -space_between_txts - left_txt_w, -small_label_y_offset - small_font_h);
    } else {
        lv_obj_align(label, ext->label[2], LV_ALIGN_OUT_BOTTOM_LEFT,
                     space_between_txts + left_txt_w, -small_label_y_offset - small_font_h);
    }
}

static void exercise_sport_ui_set_training_effect(lv_obj_t * btn, lv_coord_t arc_w,
                                                  exercise_start_ui_desc_t * desc)
{
    exercise_btn_ext_t * ext = lv_obj_get_ext_attr(btn);

    lv_coord_t small_font_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_coord_t big_font_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_BIG);

    lv_bidi_dir_t dir = lv_obj_get_base_dir(btn);

    lv_obj_t * label_2 = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(label_2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_obj_set_style_local_text_letter_space(label_2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(label_2, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
    lv_label_set_align(label_2, LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(label_2, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_2, LV_HOR_RES / 2 - 2 * arc_w);
    exercise_sport_set_item_txt(label_2, desc->item_type[0]);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(label_2, btn, LV_ALIGN_IN_RIGHT_MID, -arc_w * 3 / 2,
                     (big_font_h - small_font_h) / 2);
    } else {
        lv_obj_align(label_2, btn, LV_ALIGN_IN_LEFT_MID, arc_w * 3 / 2,
                     (big_font_h - small_font_h) / 2);
    }

    lv_obj_t * cont = lv_cont_create(btn, NULL);
    lv_obj_add_style(cont, LV_CONT_PART_MAIN, &lv_style_transp_tight);
    lv_cont_set_fit(cont, LV_FIT_TIGHT);
    lv_cont_set_layout(cont, LV_LAYOUT_OFF);

    lv_obj_t * label_1 = lv_label_create(cont, NULL);
    lv_obj_set_style_local_text_font(label_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_obj_set_style_local_text_letter_space(label_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(label_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
    lv_label_set_text(label_1, "<");

    ext->label[0] = lv_label_create(cont, NULL);
    lv_obj_set_style_local_text_font(ext->label[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_BIG);
    lv_obj_set_style_local_text_letter_space(ext->label[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(ext->label[0], LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                      LV_COLOR_GRAY);
    exercise_sport_set_item_type_and_def_value(ext->label[0], desc->item_type[0]);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(ext->label[0], label_1, LV_ALIGN_OUT_LEFT_MID, 0, 1);
    } else {
        lv_obj_align(ext->label[0], label_1, LV_ALIGN_OUT_RIGHT_MID, 0, 1);
    }

    lv_obj_align(cont, label_2, LV_ALIGN_OUT_TOP_MID, 0, 0);

    label_2 = lv_label_create(btn, label_2);
    exercise_sport_set_item_txt(label_2, desc->item_type[1]);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(label_2, btn, LV_ALIGN_IN_LEFT_MID, arc_w * 3 / 2,
                     (big_font_h - small_font_h) / 2);
    } else {
        lv_obj_align(label_2, btn, LV_ALIGN_IN_RIGHT_MID, -arc_w * 3 / 2,
                     (big_font_h - small_font_h) / 2);
    }

    cont = lv_cont_create(btn, cont);

    label_1 = lv_label_create(cont, label_1);

    ext->label[1] = lv_label_create(cont, ext->label[0]);
    exercise_sport_set_item_type_and_def_value(ext->label[1], desc->item_type[1]);
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(ext->label[1], label_1, LV_ALIGN_OUT_LEFT_MID, 0, 1);
    } else {
        lv_obj_align(ext->label[1], label_1, LV_ALIGN_OUT_RIGHT_MID, 0, 1);
    }

    lv_obj_align(cont, label_2, LV_ALIGN_OUT_TOP_MID, 0, 0);

    label_1 = lv_label_create(btn, NULL);
    lv_obj_set_style_local_text_font(label_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_NORMAL);
    lv_obj_set_style_local_text_letter_space(label_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_text_color(label_1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
    lv_label_set_align(label_1, LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(label_1, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(label_1, LV_HOR_RES - 2 * arc_w);
    lv_label_set_text_id(label_1, WATCH_TEXT_ID_TRAINING_EFFECT);
    lv_obj_align(label_1, btn, LV_ALIGN_IN_TOP_MID, 0,
                 (lv_obj_get_y(cont) + arc_w - lv_obj_get_height(label_1)) / 2);
}

static void exercise_sport_start_btn_del_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_DELETE != event) return;

    exercise_btn_ext_t * ext = lv_obj_get_ext_attr(btn);
    if(ext->info) {
        gif_close(ext->info);
    }
}

static lv_obj_t * exercise_add_sport_ui(lv_obj_t * tileview, lv_obj_t * list,
                                        exercise_start_ui_desc_t * desc)
{
    uint16_t target_pace_value = 0;
    if(EXERCISE_START_UI_TYPE_RUNNING_WITH_AI == desc->ui_type) {
        exercise_tileview_ext_t * tileview_ext = lv_obj_get_ext_attr(tileview);
        exercise_sport_info_t sport_info;
        exercise_get_sport_info(tileview_ext->item->type, &sport_info);
        exercise_nv_intel_run_comp_t * nv = (exercise_nv_intel_run_comp_t *)
            exercise_get_nv_pointer(tileview_ext->item->data,
                                    sport_info.setting_item_bitmap,
                                    EXERCISE_SETTING_ITEM_TYPE_INTEL_RUN_COMP);
        if(nv && (1 == nv->is_on) && (0 != nv->value)) {
            target_pace_value = nv->value;
        } else {
            printf("%s: no target pace value\n", __FUNCTION__);
            return(NULL);
        }
    }

    lv_obj_t * btn = lv_list_add_btn(list, NULL, NULL);
    exercise_btn_ext_t * ext = lv_obj_allocate_ext_attr(btn, sizeof(exercise_btn_ext_t));
    LV_ASSERT_MEM(ext);
    for(uint8_t i = 0;i < EXERCISE_MAX_ITEM_NUM_PER_START_UI;i++) {
        ext->label[i] = NULL;
    }
    ext->time_label = NULL;
    ext->arc_type = desc->arc_type;
    ext->color_index = 0xff; // invalid color index
    ext->info = NULL;

    lv_btn_set_fit(btn, LV_FIT_NONE);
    lv_btn_set_layout(btn, LV_LAYOUT_OFF);
    lv_obj_set_size(btn, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_opa(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_obj_set_style_local_bg_opa(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_BLACK);
    lv_obj_set_style_local_bg_grad_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_BLACK);
    lv_obj_set_style_local_radius(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_click(btn, false);
    lv_obj_set_event_cb(btn, exercise_sport_start_btn_del_cb);
    lv_tileview_add_element(tileview, btn);

    lv_bidi_dir_t dir = lv_obj_get_base_dir(btn);
    lv_coord_t arc_w = LV_HOR_RES / 20;
    if(EXERCISE_ARC_TYPE_HR == desc->arc_type) {
        lv_color_t color[EXERCISE_MAX_HR_ZONE_NUM]
            = {LV_COLOR_BLUE, LV_COLOR_MAKE(0x00, 0xFF, 0x40), LV_COLOR_YELLOW, LV_COLOR_ORANGE,
               LV_COLOR_RED};
        lv_opa_t opa[EXERCISE_MAX_HR_ZONE_NUM]
            = {LV_OPA_50, LV_OPA_50, LV_OPA_50, LV_OPA_50, LV_OPA_50};
        int32_t step_angle = EXERCISE_HR_ARC_ANGLE / EXERCISE_MAX_HR_ZONE_NUM;
        int32_t start_angle;
        if(LV_BIDI_DIR_RTL == dir) {
            start_angle = 270 + EXERCISE_HR_ARC_ANGLE / 2;
        } else {
            start_angle = 270 - EXERCISE_HR_ARC_ANGLE / 2;
        }
        lv_obj_t * arc[EXERCISE_MAX_HR_ZONE_NUM];
        for(uint8_t i = 0;i < EXERCISE_MAX_HR_ZONE_NUM;i++) {
            arc[i] = lv_arc_create(btn, NULL);
            lv_obj_set_size(arc[i], LV_HOR_RES, LV_VER_RES);
            lv_obj_align(arc[i], btn, LV_ALIGN_CENTER, 0, 0);
            if(LV_BIDI_DIR_RTL == dir) {
                lv_arc_set_bg_angles(arc[i], start_angle - step_angle, start_angle);
                start_angle -= step_angle;
            } else {
                lv_arc_set_bg_angles(arc[i], start_angle, start_angle + step_angle);
                start_angle += step_angle;
            }
            lv_obj_set_style_local_bg_opa(arc[i], LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
            lv_obj_set_style_local_line_rounded(arc[i], LV_ARC_PART_BG, LV_STATE_DEFAULT, false);
            lv_obj_set_style_local_line_color(arc[i], LV_ARC_PART_BG, LV_STATE_DEFAULT, color[i]);
            lv_obj_set_style_local_line_opa(arc[i], LV_ARC_PART_BG, LV_STATE_DEFAULT, opa[i]);
            lv_obj_set_style_local_line_width(arc[i], LV_ARC_PART_BG, LV_STATE_DEFAULT, arc_w);
            lv_tileview_add_element(tileview, arc[i]);
        }

        lv_obj_t * cont = lv_cont_create(btn, NULL);
        lv_obj_add_style(cont, LV_CONT_PART_MAIN, &lv_style_transp_tight);
        lv_obj_set_style_local_bg_opa(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
        lv_obj_set_style_local_bg_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
        lv_cont_set_fit(cont, LV_FIT_TIGHT);
        lv_obj_set_click(cont, false);
        lv_obj_set_hidden(cont, true);
        ext->hr_state_cont = cont;

        lv_obj_t * arc_state_label = lv_label_create(cont, NULL);
        lv_obj_set_style_local_text_font(arc_state_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                         LV_THEME_WATCH_NIGHT_FONT_SMALL);
        lv_obj_set_style_local_text_letter_space(arc_state_label, LV_LABEL_PART_MAIN,
                                                 LV_STATE_DEFAULT, 0);
        lv_obj_set_style_local_text_color(arc_state_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                          LV_COLOR_BLACK);
        lv_label_set_align(arc_state_label, LV_LABEL_ALIGN_CENTER);
        lv_label_set_long_mode(arc_state_label, LV_LABEL_LONG_SROLL_CIRC);
        lv_coord_t arc_state_label_h = lv_obj_get_height(arc_state_label);
        lv_obj_set_width(arc_state_label, 4 * arc_state_label_h);

        lv_obj_set_style_local_radius(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, arc_state_label_h);
        lv_obj_align(cont, btn, LV_ALIGN_IN_TOP_MID, 0, arc_w * 2);

        ext->pointer_img = lv_img_create(btn, NULL);
        lv_img_set_src(ext->pointer_img, ICON_EXERCISE_TRIANGLE);
        lv_coord_t img_w = lv_obj_get_width(ext->pointer_img);
        lv_img_set_zoom(ext->pointer_img, LV_IMG_ZOOM_NONE * arc_w / img_w);
        // the distance from center to the left side of img
        lv_coord_t radius = LV_HOR_RES / 2 - arc_w / 5 - arc_w / 2 - img_w / 2;
        lv_coord_t pivot_x = radius * img_w / arc_w; // radius / zoom
        lv_img_set_pivot(ext->pointer_img, -pivot_x, lv_obj_get_height(ext->pointer_img) / 2);
        lv_obj_align(ext->pointer_img, btn, LV_ALIGN_IN_RIGHT_MID,
                     radius * img_w / arc_w + img_w - LV_HOR_RES / 2, 0);
        lv_obj_set_hidden(ext->pointer_img, true);
    } else if(EXERCISE_ARC_TYPE_TRAINING_EFFECT == desc->arc_type) {
        int32_t start_angle_1 = 180 - EXERCISE_TRANING_EFFECT_ARC_ANGLE / 2;
        int32_t end_angle_1 = start_angle_1 + EXERCISE_TRANING_EFFECT_ARC_ANGLE;
        int32_t start_angle_2 = 360 - EXERCISE_TRANING_EFFECT_ARC_ANGLE / 2;
        int32_t end_angle_2 = start_angle_2 + EXERCISE_TRANING_EFFECT_ARC_ANGLE;

        lv_obj_t * arc[2];
        arc[0] = lv_arc_create(btn, NULL);
        lv_obj_set_size(arc[0], LV_HOR_RES, LV_VER_RES);
        lv_obj_set_style_local_bg_opa(arc[0], LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
        lv_obj_set_style_local_line_rounded(arc[0], LV_ARC_PART_BG, LV_STATE_DEFAULT, false);
        lv_obj_set_style_local_line_color(arc[0], LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_COLOR_GRAY);
        lv_obj_set_style_local_line_opa(arc[0], LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_50);
        lv_obj_set_style_local_line_width(arc[0], LV_ARC_PART_BG, LV_STATE_DEFAULT, arc_w);
        lv_obj_set_style_local_line_color(arc[0], LV_ARC_PART_INDIC, LV_STATE_DEFAULT,
                                          LV_COLOR_YELLOW);
        lv_obj_set_style_local_line_opa(arc[0], LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_OPA_90);
        lv_obj_set_style_local_line_rounded(arc[0], LV_ARC_PART_INDIC, LV_STATE_DEFAULT, false);
        lv_obj_set_style_local_line_width(arc[0], LV_ARC_PART_INDIC, LV_STATE_DEFAULT, arc_w);
        lv_obj_align(arc[0], btn, LV_ALIGN_CENTER, 0, 0);
        lv_tileview_add_element(tileview, arc[0]);

        arc[1] = lv_arc_create(btn, arc[0]);
        lv_obj_set_style_local_line_color(arc[1], LV_ARC_PART_INDIC, LV_STATE_DEFAULT,
                                          LV_COLOR_MAKE(0x00, 0xFF, 0x40));
        lv_obj_set_style_local_line_opa(arc[1], LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_OPA_COVER);
        lv_obj_set_size(arc[1], LV_HOR_RES, LV_VER_RES);
        lv_obj_align(arc[1], btn, LV_ALIGN_CENTER, 0, 0);
        lv_tileview_add_element(tileview, arc[1]);

        if(LV_BIDI_DIR_RTL == dir) {
            lv_arc_set_bg_angles(arc[1], start_angle_1, end_angle_1);
            lv_arc_set_bg_angles(arc[0], start_angle_2, end_angle_2);
        } else {
            lv_arc_set_bg_angles(arc[0], start_angle_1, end_angle_1);
            lv_arc_set_bg_angles(arc[1], start_angle_2, end_angle_2);
        }
    }

    if(EXERCISE_START_UI_TYPE_4_ITEMS_WITH_TIME == desc->ui_type) {
        exercise_sport_ui_set_4_items_with_time(btn, arc_w, desc, ext->hr_state_cont);
    } else if(EXERCISE_START_UI_TYPE_3_ITEMS_WITH_TIME == desc->ui_type) {
        exercise_sport_ui_set_3_items_with_time(btn, arc_w, desc);
    } else if(EXERCISE_START_UI_TYPE_2_ITEMS_WITH_TIME == desc->ui_type) {
        exercise_sport_ui_set_2_items_with_time(btn, arc_w, desc);
    } else if(EXERCISE_START_UI_TYPE_1_ITEM_WITH_TIME == desc->ui_type) {
        exercise_sport_ui_set_1_item_with_time(btn, arc_w, desc);
    } else if(EXERCISE_START_UI_TYPE_RUNNING_WITH_AI == desc->ui_type) {
        exercise_sport_ui_set_running_with_ai(btn, target_pace_value);
    } else if(EXERCISE_START_UI_TYPE_TRAINING_EFFECT == desc->ui_type) {
        exercise_sport_ui_set_training_effect(btn, arc_w, desc);
    } else {
        printf("%s: warning, wrong ui type %d\n", __FUNCTION__, desc->ui_type);
    }

    switch(desc->ui_type) {
    case EXERCISE_START_UI_TYPE_4_ITEMS_WITH_TIME:
    case EXERCISE_START_UI_TYPE_3_ITEMS_WITH_TIME:
    case EXERCISE_START_UI_TYPE_2_ITEMS_WITH_TIME:
    case EXERCISE_START_UI_TYPE_1_ITEM_WITH_TIME:
        ext->time_label = lv_label_create(btn, NULL);
        lv_obj_set_style_local_text_font(ext->time_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                         LV_THEME_WATCH_NIGHT_FONT_NORMAL);
        lv_obj_set_style_local_text_letter_space(ext->time_label, LV_LABEL_PART_MAIN,
                                                 LV_STATE_DEFAULT, 0);
        lv_obj_set_style_local_text_color(ext->time_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                          LV_COLOR_WHITE);
        lv_label_set_align(ext->time_label, LV_LABEL_ALIGN_CENTER);
        lv_label_set_long_mode(ext->time_label, LV_LABEL_LONG_SROLL_CIRC);
        lv_obj_set_width(ext->time_label, LV_HOR_RES - 2 * arc_w);
        break;
    }

    return(btn);
}

static void exercise_titleview_set_leds(lv_obj_t * tileview, uint8_t tileview_num)
{
    exercise_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);

    printf("%s: act x %d\n", __FUNCTION__, ext->old_ext.act_id.x);

    lv_coord_t font_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_NORMAL);
    bool is_leds_cont_present = true;
    if(NULL == ext->leds_cont) {
        is_leds_cont_present = false;
        ext->leds_cont = lv_cont_create(tileview, NULL);
        lv_cont_set_fit2(ext->leds_cont, LV_FIT_TIGHT, LV_FIT_NONE);
        lv_cont_set_layout(ext->leds_cont, LV_LAYOUT_ROW_MID);
        lv_obj_add_style(ext->leds_cont, LV_CONT_PART_MAIN, &lv_watch_style_transp);
        lv_obj_set_click(ext->leds_cont, false);
        lv_obj_set_height(ext->leds_cont, font_h / 3);
    }

    if(!LAUNCHER_LED_ENABLE || (2 > tileview_num)) {
        lv_obj_set_pos(ext->leds_cont,
                       (lv_obj_get_width(tileview) - lv_obj_get_width(ext->leds_cont)) / 2 +
                       LV_HOR_RES * ext->old_ext.act_id.x,
                       lv_obj_get_height(tileview) - 2 * lv_obj_get_height(ext->leds_cont));
        return;
    }

    uint8_t i;
    lv_obj_t * leds[tileview_num];
    if(!is_leds_cont_present) {
        for(i = 0;i < tileview_num;i++) {
            leds[i] = lv_led_create(ext->leds_cont, NULL);
        }
    } else {
        leds[0] = lv_obj_get_child_back(ext->leds_cont, NULL);
        for(i = 1;i < tileview_num;i++) {
            leds[i] = lv_obj_get_child_back(ext->leds_cont, leds[i - 1]);
        }
    }

    uint8_t act_id_x = ext->old_ext.act_id.x;
    if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(ext->leds_cont)) {
        act_id_x = tileview_num - 1 - act_id_x;
    }
    for(i = 0;i < tileview_num;i++) {
        if(i == act_id_x) {
            lv_led_on(leds[i]);
            lv_obj_set_size(leds[i], font_h / 3, font_h / 3);
        } else {
            lv_led_off(leds[i]);
            lv_obj_set_size(leds[i], font_h / 4, font_h / 4);
        }
    }

    lv_obj_set_pos(ext->leds_cont,
                   (lv_obj_get_width(tileview) - lv_obj_get_width(ext->leds_cont)) / 2 +
                   LV_HOR_RES * ext->old_ext.act_id.x,
                   lv_obj_get_height(tileview) - 2 * lv_obj_get_height(ext->leds_cont));
}

uint8_t exercise_sport_get_tileview_num(void)
{
    uint8_t tileview_num = 1;
#if USE_LV_WATCH_AUDIO_PLAYER != 0
    tileview_num++;
#endif
#if USE_LV_WATCH_QRCODE != 0
    tileview_num++;
#endif
    return tileview_num;
}

static void exercise_tileview_cb(lv_obj_t * obj, lv_event_t event)
{
    if(LV_EVENT_VALUE_CHANGED == event) {
        exercise_titleview_set_leds(obj, exercise_sport_get_tileview_num());
    }
}

static void exercise_sport_list_cb(lv_obj_t * list, lv_event_t event)
{
    if(LV_EVENT_DELETE != event) return;

    printf("%s\n", __FUNCTION__);

    exercise_list_ext_t * ext = lv_obj_get_ext_attr(list);
    if(ext->update_task) lv_task_del(ext->update_task);
}

static void exercise_scrl_drag_end_cb(lv_obj_t * scrl, lv_event_t event)
{
    if(LV_EVENT_DRAG_END != event) return;

    lv_coord_t pos_y = lv_obj_get_y(scrl);
    uint8_t index = -pos_y / LV_VER_RES;
    if((LV_VER_RES / 2) < (-pos_y % LV_VER_RES)) index++;
    lv_obj_t * btn = lv_obj_get_child_back(scrl, NULL);
    uint8_t i = 0;
    lv_obj_t * focus_btn = NULL;
    lv_obj_t * list = lv_obj_get_parent(scrl);
    while(btn) {
        if(index == i) {
            focus_btn = btn;
            lv_list_focus_btn(list, focus_btn);
        }
        i++;
        btn = lv_obj_get_child_back(scrl, btn);
    }
    if(3 > i) return;

    if((0 == index) || (i == (index + 1))) {
        uint16_t anim_time = lv_list_get_anim_time(list);
        lv_list_set_anim_time(list, 0);
        if(0 == index) {
            // focus the first btn
            _lv_ll_move_before(&scrl->child_ll, lv_obj_get_child(scrl, NULL), NULL);
        } else {
            // focus the last btn
            _lv_ll_move_before(&scrl->child_ll, lv_obj_get_child_back(scrl, NULL),
                               lv_obj_get_child(scrl, NULL));
        }
        scrl->signal_cb(scrl, LV_SIGNAL_CHILD_CHG, NULL);
        lv_list_focus_btn(list, focus_btn);
        lv_list_set_anim_time(list, anim_time);
    }
}

static void exercise_sport_start_destroy(lv_obj_t * activity_obj)
{
    printf("%s\n", __FUNCTION__);
    lv_obj_t * tileview = lv_obj_get_child_back(activity_obj, NULL);
    exercise_tileview_ext_t * ext = lv_obj_get_ext_attr(tileview);
    if(ext->valid_pos) {
        lv_mem_free(ext->valid_pos);
    }
#if USE_LV_WATCH_AUDIO_PLAYER != 0
    audio_player_destroy_tab(ext->audio_player_cont);
#endif
    exercise_sport_stop_req();
    watch_set_suspend_enable(true, ACT_ID_EXERCISE_SPORT, false);
    lv_watch_png_cache_all_free();
}

static void exercise_sport_start_create(exercise_start_desc_t * desc, exercise_item_t * item,
                                        bool is_wakey)
{
    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_EXERCISE_SPORT);
    if(NULL == activity_obj) {
        printf("%s: warning, activity_obj is NULL\n", __FUNCTION__);
        return;
    }

    lv_watch_activity_ext_t * activity_ext = lv_obj_get_ext_attr(activity_obj);
    activity_ext->prepare_destory = exercise_sport_start_destroy;

    lv_obj_clean(activity_obj);

    lv_obj_t * tileview = lv_tileview_create(activity_obj, NULL);
    exercise_tileview_ext_t * ext = lv_obj_allocate_ext_attr(tileview,
                                                             sizeof(exercise_tileview_ext_t));
    LV_ASSERT_MEM(ext);

    ext->item = item;
    ext->is_wakey = is_wakey;

    uint8_t tileview_num = exercise_sport_get_tileview_num();
    ext->valid_pos = lv_mem_alloc(sizeof(lv_point_t) * tileview_num);
    for(uint8_t i = 0;i < tileview_num;i++) {
        ext->valid_pos[i].x = i;
        ext->valid_pos[i].y = 0;
    }
    ext->leds_cont = NULL;
    ext->pause_cont = NULL;
    ext->stop_cont = NULL;

    lv_tileview_set_valid_positions(tileview, ext->valid_pos, tileview_num);
    lv_tileview_set_edge_flash(tileview, true);
    lv_tileview_set_anim_time(tileview, 40);
    lv_page_set_scrollbar_mode(tileview, LV_SCROLLBAR_MODE_OFF);
    lv_obj_add_style(tileview, LV_TILEVIEW_PART_EDGE_FLASH, &lv_watch_cont_opa1);
    if(1 < tileview_num) {
        lv_obj_set_event_cb(tileview, exercise_tileview_cb);
    }

    lv_bidi_dir_t dir = lv_obj_get_base_dir(tileview);

    lv_obj_t * list = lv_list_create(tileview, NULL);
    exercise_list_ext_t * list_ext = lv_obj_allocate_ext_attr(list,
                                                              sizeof(exercise_list_ext_t));
    LV_ASSERT_MEM(list_ext);
    lv_obj_set_event_cb(list, exercise_sport_list_cb);

    hal_rtc_t time;
    Hal_Rtc_Gettime(&time);
    list_ext->start_time = time_to_seconds(&time);

    lv_obj_set_size(list, LV_HOR_RES, LV_VER_RES);
    lv_obj_add_style(list, LV_LIST_PART_BG, &lv_style_transp_tight);
    lv_list_set_scrollbar_mode(list, LV_SCROLLBAR_MODE_OFF);
    lv_list_set_scroll_propagation(list, true);
    uint8_t pos = 0;
    if(LV_BIDI_DIR_RTL == dir) {
        pos = tileview_num - 1;
    }
    lv_obj_set_x(list, LV_HOR_RES * ext->valid_pos[pos].x);
    lv_tileview_add_element(tileview, list);
    lv_obj_t * scrl = lv_page_get_scrollable(list);
    lv_obj_set_event_cb(scrl, exercise_scrl_drag_end_cb);
    lv_obj_set_drag_throw(scrl, false);

    lv_obj_t * btn;
    if(0 < desc->ui_count) {
        uint8_t count = desc->ui_count;
        // create the last btn at first
        exercise_add_sport_ui(tileview, list, &desc->ui_desc[count - 1]);
        count--;
        for(uint8_t i = 0;i < count;i++) {
            btn = exercise_add_sport_ui(tileview, list, &desc->ui_desc[i]);
            if(0 == i) {
                uint16_t anim_time = lv_list_get_anim_time(list);
                lv_list_set_anim_time(list, 0);
                lv_list_focus_btn(list, btn);
                lv_list_set_anim_time(list, anim_time);
            }
        }
        if(2 == desc->ui_count) {
            for(int8_t i = 1;i >= 0;i--) {
                exercise_add_sport_ui(tileview, list, &desc->ui_desc[i]);
            }
        }
    }

#if USE_LV_WATCH_AUDIO_PLAYER != 0
    ext->audio_player_cont = lv_cont_create(tileview, NULL);
    lv_obj_set_size(ext->audio_player_cont, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_opa(ext->audio_player_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(ext->audio_player_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    if(LV_BIDI_DIR_RTL == dir) {
        pos--;
    } else {
        pos++;
    }
    lv_obj_set_x(ext->audio_player_cont, LV_HOR_RES * ext->valid_pos[pos].x);
    lv_obj_set_click(ext->audio_player_cont, false);
    lv_tileview_add_element(tileview, ext->audio_player_cont);

    audio_player_create_tab(ext->audio_player_cont);
#endif

#if USE_LV_WATCH_QRCODE != 0
    lv_obj_t * cont = lv_cont_create(tileview, NULL);
    lv_obj_set_size(cont, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_style_local_bg_opa(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_obj_set_click(cont, false);
    if(LV_BIDI_DIR_RTL == dir) {
        pos--;
    } else {
        pos++;
    }
    lv_obj_set_x(cont, LV_HOR_RES * ext->valid_pos[pos].x);
    lv_tileview_add_element(tileview, cont);

    lv_obj_t * qr_obj = qrcode_create(NULL);
    lv_obj_t * qr_content = lv_obj_get_child_back(qr_obj, NULL);
    lv_obj_set_parent(qr_content, cont);
    lv_obj_align(qr_content, cont, LV_ALIGN_CENTER, 0, 0);
    lv_obj_del(lv_obj_get_parent(lv_obj_get_parent(qr_obj)));

    if(LV_BIDI_DIR_RTL == dir) {
        pos = tileview_num - 1;
        lv_tileview_set_tile_act(tileview, ext->valid_pos[pos].x,
                                 ext->valid_pos[pos].y, LV_ANIM_OFF);
    }
#endif

    exercise_titleview_set_leds(tileview, tileview_num);

    char time_str[6];
    snprintf(time_str, 6, "%02d:%02d", time.tm_hour, time.tm_min);
    btn = lv_list_get_next_btn(list, NULL);
    while(btn) {
        exercise_btn_ext_t * btn_ext = lv_obj_get_ext_attr(btn);
        if(btn_ext->time_label) {
            lv_obj_set_base_dir(btn_ext->time_label, LV_BIDI_DIR_LTR);
            lv_label_set_text(btn_ext->time_label, time_str);
            lv_obj_align(btn_ext->time_label, btn, LV_ALIGN_IN_BOTTOM_MID, 0,
                         lv_obj_get_y(ext->leds_cont) - LV_VER_RES);
        }
        btn = lv_list_get_next_btn(list, btn);
    }

    list_ext->update_task = lv_task_create(exercise_sport_start_update_task_cb, 1000,
                                           LV_TASK_PRIO_HIGH, list);
}

static void exercise_sport_preparation_update_task_cb(lv_task_t * task)
{
    exercise_sport_ext_t * ext = task->user_data;

    hal_rtc_t time;
    Hal_Rtc_Gettime(&time);
    char str[10];

    if(12 < time.tm_hour) {
        snprintf(str, 10, "%02d:%02d PM", time.tm_hour - 12, time.tm_min);
    } else {
        snprintf(str, 10, "%02d:%02d AM", time.tm_hour, time.tm_min);
    }
    lv_label_set_text(ext->time_label, str);

#if EXERCISE_TEST_MODE != 0
    exercise_test_sport_data_t sport_data = {};
    exercise_get_sport_data(&sport_data);
    if(0 < sport_data.hr_value) {
        exercise_int_to_str(sport_data.hr_value, str, 10);
        lv_label_set_text(ext->hr_label, str);
    }
#endif

    uint8_t bat_status = Hal_Battery_Get_Status();
    if(lv_watch_get_free_num(ext->bat_cont) == bat_status) {
        lv_watch_set_free_num(ext->bat_cont, bat_status);
        lv_obj_t * label_bat_percent = lv_obj_get_child(ext->bat_cont, NULL);
        snprintf(str, 10, "%02d%%", bat_status);
        lv_label_set_text(label_bat_percent, str);
    }
}

static void exercise_sport_preparation_btn_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    exercise_sport_ext_t * ext = exercise_get_ext(ACT_ID_EXERCISE_SPORT);
    printf("%s: start sport type %d\n", __FUNCTION__, ext->item->type);
    exercise_sport_info_t sport_info;
    exercise_get_sport_info(ext->item->type, &sport_info);
    exercise_start_desc_t desc = {};
    sport_info.start_cb(&desc);
    bool is_wakey = false;
    if(0 != (sport_info.setting_item_bitmap & (1 << EXERCISE_SETTING_ITEM_TYPE_WAKEY))) {
        exercise_nv_wakey_t * nv
            = (exercise_nv_wakey_t *)exercise_get_nv_pointer(ext->item->data,
                                                             sport_info.setting_item_bitmap,
                                                             EXERCISE_SETTING_ITEM_TYPE_WAKEY);
        if(nv->is_wakey) {
            watch_set_suspend_enable(false, ACT_ID_EXERCISE_SPORT, false);
            is_wakey = true;
        }
    }
    exercise_sport_start_create(&desc, ext->item, is_wakey);
    exercise_sport_start_req();
}

static void exercise_sport_preparation_keep_waiting_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    exercise_sport_ext_t * ext = exercise_get_ext(ACT_ID_EXERCISE_SPORT);
    lv_obj_del(ext->wait_gps_cont);
    ext->wait_gps_cont = NULL;
}

static void exercise_sport_preparation_discard_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    exercise_sport_ext_t * ext = exercise_get_ext(ACT_ID_EXERCISE_SPORT);
    exercise_sport_preparation_btn_cb(ext->btn, LV_EVENT_CLICKED);
}

static void exercise_sport_preparation_down_func_key_cb(lv_obj_t * obj)
{
    if(NULL == obj) return;

    exercise_sport_ext_t * ext = lv_obj_get_ext_attr(obj);
    if(NULL == ext) return;

    if(ext->wait_gps_cont) {
        printf("%s: keep waiting for gps connection\n", __FUNCTION__);
        lv_obj_del(ext->wait_gps_cont);
        ext->wait_gps_cont = NULL;
    } else {
        if(ext->gps_cont && lv_anim_get(ext->gps_cont, NULL)) {
            printf("%s: ask for keeping waiting for gps connection\n", __FUNCTION__);
            lv_obj_t * par = lv_obj_get_parent(ext->note_label);
            ext->wait_gps_cont = lv_cont_create(par, par);
            lv_obj_align(ext->wait_gps_cont, par, LV_ALIGN_CENTER, 0, 0);

            lv_coord_t par_w = lv_obj_get_width(par);
            lv_coord_t font_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_NORMAL);
            lv_obj_t * label = lv_label_create(ext->wait_gps_cont, NULL);
            lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                             LV_THEME_WATCH_NIGHT_FONT_NORMAL);
            lv_obj_set_style_local_text_letter_space(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
            lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
            lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
            lv_obj_set_width(label, par_w * 5 / 7);
            lv_label_set_text_id(label, WATCH_TEXT_ID_POSITIONING_AND_START);
            if((LV_VER_RES / 2 - font_h * 2 / 3) < lv_obj_get_height(label)) {
                lv_obj_align(label, ext->wait_gps_cont, LV_ALIGN_CENTER, 0,
                             -lv_obj_get_height(label) / 2 + font_h / 3);
            } else {
                lv_obj_align(label, ext->wait_gps_cont, LV_ALIGN_CENTER, 0,
                             -lv_obj_get_height(label) / 2 - font_h / 3);
            }

            lv_obj_t * btn = lv_btn_create(ext->wait_gps_cont, NULL);
            lv_btn_set_fit2(btn, LV_FIT_NONE, LV_FIT_TIGHT);
            lv_obj_set_style_local_bg_opa(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_70);
            lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
            lv_obj_set_style_local_pad_top(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, font_h / 3);
            lv_obj_set_style_local_pad_bottom(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, font_h / 3);
            lv_obj_set_style_local_text_font(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT,
                                             LV_THEME_WATCH_NIGHT_FONT_NORMAL);
            lv_obj_set_style_local_text_letter_space(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);
            lv_obj_set_style_local_text_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT,
                                              LV_COLOR_ORANGE);
            lv_obj_set_style_local_text_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED,
                                              LV_COLOR_WHITE);
            lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_GRAY);
            lv_obj_set_width(btn, par_w * 4 / 7);
            lv_obj_set_event_cb(btn, exercise_sport_preparation_keep_waiting_cb);

            label = lv_label_create(btn, NULL);
            lv_obj_clean_style_list(label, LV_LABEL_PART_MAIN);
            lv_label_set_text_id(label, WATCH_TEXT_ID_KEEP_WAITING);

            lv_obj_align(btn, ext->wait_gps_cont, LV_ALIGN_CENTER, 0,
                         lv_obj_get_height(btn) / 2 + font_h / 3);

            lv_obj_t * discard_btn = lv_btn_create(ext->wait_gps_cont, btn);
            label = lv_label_create(discard_btn, label);
            lv_label_set_text_id(label, WATCH_TEXT_ID_IGNORE);
            lv_obj_set_event_cb(discard_btn, exercise_sport_preparation_discard_cb);

            lv_obj_align(discard_btn, btn, LV_ALIGN_OUT_BOTTOM_MID, 0, font_h / 3);
        } else {
            exercise_sport_preparation_btn_cb(ext->btn, LV_EVENT_CLICKED);
        }
    }
}

static lv_coord_t exercise_set_heart_zoom(lv_obj_t * img)
{
    uint8_t zoom_step = lv_watch_get_free_num(img);
    lv_coord_t small_img_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_coord_t big_img_h = small_img_h * 5 / 4;
    if(0 == zoom_step) {
        lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * small_img_h / lv_obj_get_height(img));
        lv_watch_set_free_num(img, 1);
    } else {
        lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * big_img_h / lv_obj_get_height(img));
        lv_watch_set_free_num(img, 0);
    }
    return(big_img_h);
}

static void exercise_heart_anim_cb(lv_anim_t * a)
{
    exercise_set_heart_zoom((lv_obj_t *)a->var);
}

static void exercise_gps_anim_cb(lv_anim_t * a)
{
    lv_obj_t * cont = (lv_obj_t *)a->var;
    lv_obj_t * signal_cont = lv_obj_get_child_back(cont, NULL);
    uint8_t step = lv_watch_get_free_num(cont);
    if(0 == step) {
        lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_WHITE);
        lv_watch_set_free_num(cont, 1);
    } else if(1 == step) {
        signal_cont = lv_obj_get_child_back(cont, signal_cont);
        lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_WHITE);
        lv_watch_set_free_num(cont, 2);
    } else if(2 == step) {
        signal_cont = lv_obj_get_child_back(cont, signal_cont);
        signal_cont = lv_obj_get_child_back(cont, signal_cont);
        lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_WHITE);
        lv_watch_set_free_num(cont, 3);
    } else if(3 == step) {
        lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_GRAY);
        signal_cont = lv_obj_get_child_back(cont, signal_cont);
        lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_GRAY);
        signal_cont = lv_obj_get_child_back(cont, signal_cont);
        lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_GRAY);
        lv_watch_set_free_num(cont, 0);
    }
}

static void exercise_set_bat_label(lv_obj_t * label, uint8_t bat_status)
{
    if(90 <= bat_status) {
        lv_label_set_text(label, LV_SYMBOL_BATTERY_FULL);
    } else if(65 <= bat_status) {
        lv_label_set_text(label, LV_SYMBOL_BATTERY_3);
    } else if(40 <= bat_status) {
        lv_label_set_text(label, LV_SYMBOL_BATTERY_2);
    } else if(15 <= bat_status) {
        lv_label_set_text(label, LV_SYMBOL_BATTERY_1);
    } else {
        lv_label_set_text(label, LV_SYMBOL_BATTERY_EMPTY);
    }
}

#if EXERCISE_TEST_MODE != 0
static void exercise_sport_prepare_cnf(void)
{
    printf("%s\n", __FUNCTION__);

    exercise_sport_ext_t * ext = exercise_get_ext(ACT_ID_EXERCISE_SPORT);
    if((NULL == ext) || (NULL == ext->btn)) {
        printf("%s: warning, rcv cnf at the wrong time\n", __FUNCTION__);
        return;
    }

    if(NULL == ext->gps_cont) return;

    lv_anim_del(ext->gps_cont, NULL);
    lv_obj_t * signal_cont = lv_obj_get_child_back(ext->gps_cont, NULL);
    lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                    LV_COLOR_WHITE);
    signal_cont = lv_obj_get_child_back(ext->gps_cont, signal_cont);
    lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                    LV_COLOR_WHITE);
    signal_cont = lv_obj_get_child_back(ext->gps_cont, signal_cont);
    lv_obj_set_style_local_bg_color(signal_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                    LV_COLOR_WHITE);

    lv_label_set_text_id(ext->note_label, WATCH_TEXT_ID_READY_AND_CLICK_TO_START);

    lv_obj_set_style_local_bg_color(ext->btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT,
                                    LV_COLOR_MAKE(0x00, 0xD0, 0x29));
    lv_obj_set_style_local_bg_color(ext->btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED,
                                    LV_COLOR_MAKE(0x00, 0xFF, 0x40));
    lv_obj_set_event_cb(ext->btn, exercise_sport_preparation_btn_cb);
}
#endif

static void exercise_sport_obj_delete_cb(lv_obj_t * obj, lv_event_t event)
{
    if(LV_EVENT_DELETE != event) return;

    exercise_sport_ext_t * ext = lv_obj_get_ext_attr(obj);
    lv_task_del(ext->update_task);
}

static void exercise_sport_prepare_destroy(lv_obj_t * activity_obj)
{
    printf("%s\n", __FUNCTION__);
    exercise_sport_stop_req();
    watch_set_suspend_enable(true, ACT_ID_EXERCISE_SPORT, false);
    lv_watch_png_cache_all_free();
}

static void exercise_sport_preparation_create(exercise_item_t * item, bool is_wait_gps,
                                              void * img_src)
{
    printf("%s: type %d, is_wait_gps %d\n", __FUNCTION__, item->type, is_wait_gps);

    lv_watch_activity_ext_t activity_ext = {};
    activity_ext.actId = ACT_ID_EXERCISE_SPORT;
    activity_ext.create = NULL;
    activity_ext.prepare_destory = exercise_sport_prepare_destroy;
    lv_obj_t * activity_obj = lv_watch_creat_activity_obj(&activity_ext);
    LV_ASSERT_MEM(activity_obj);

    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);
    exercise_sport_ext_t * ext = lv_obj_allocate_ext_attr(obj, sizeof(exercise_sport_ext_t));
    LV_ASSERT_MEM(ext);
    lv_obj_set_event_cb(obj, exercise_sport_obj_delete_cb);

    ext->item = item;
    ext->wait_gps_cont = NULL;

    lv_coord_t font_h = lv_font_get_line_height(LV_THEME_WATCH_NIGHT_FONT_SMALL);

    lv_obj_t * bg = lv_cont_create(obj, NULL);
    lv_obj_set_style_local_bg_opa(bg, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
    lv_obj_set_style_local_bg_color(bg, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_obj_set_size(bg, LV_HOR_RES, LV_VER_RES);
    lv_obj_set_click(bg, false);
    lv_obj_align(bg, obj, LV_ALIGN_CENTER, 0, 0);

    lv_coord_t space = LV_VER_RES / 7;
    lv_coord_t btn_size = space * 3;
    lv_obj_t * btn = lv_btn_create(bg, NULL);
    if(false == is_wait_gps) {
        lv_obj_set_event_cb(btn, exercise_sport_preparation_btn_cb);
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_MAKE(0x00, 0xFF, 0x40));
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED,
                                        LV_COLOR_MAKE(0x00, 0xFF, 0x40));
    } else {
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY);
        lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_GRAY);
    }
    lv_obj_set_style_local_radius(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
    lv_obj_set_size(btn, btn_size, btn_size);
    lv_obj_align(btn, bg, LV_ALIGN_CENTER, 0, 0);
    lv_watch_obj_add_element(btn);
    ext->btn = btn;

    lv_obj_t * img = lv_img_create(btn, NULL);
    lv_img_set_src(img, img_src);
    lv_obj_align(img, btn, LV_ALIGN_CENTER, 0, 0);
    lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * btn_size * 3 / (4 * lv_obj_get_height(img)));

    ext->time_label = lv_label_create(bg, NULL);
    lv_obj_set_base_dir(ext->time_label, LV_BIDI_DIR_LTR);
    lv_obj_set_style_local_text_font(ext->time_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_obj_set_style_local_text_letter_space(ext->time_label, LV_LABEL_PART_MAIN,
                                             LV_STATE_DEFAULT, 0);
    lv_label_set_align(ext->time_label, LV_LABEL_ALIGN_CENTER);
    lv_label_set_long_mode(ext->time_label, LV_LABEL_LONG_SROLL_CIRC);
    lv_obj_set_width(ext->time_label, LV_HOR_RES);
    uint8_t space_ver_num = 4;
    lv_coord_t space_ver = (2 * space - 2 * font_h) / space_ver_num;
    lv_obj_align(ext->time_label, bg, LV_ALIGN_IN_TOP_MID, 0, (space_ver_num - 1) * space_ver);

    ext->bat_cont = lv_cont_create(bg, NULL);
    lv_obj_set_click(ext->bat_cont, false);
    lv_obj_set_style_local_bg_opa(ext->bat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0);
    lv_obj_set_style_local_pad_top(ext->bat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_pad_bottom(ext->bat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
    lv_obj_set_style_local_pad_inner(ext->bat_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, font_h / 4);
    lv_cont_set_fit2(ext->bat_cont, LV_FIT_TIGHT, LV_FIT_NONE);
    lv_cont_set_layout(ext->bat_cont, LV_LAYOUT_ROW_MID);
    lv_obj_set_height(ext->bat_cont, font_h);
    lv_obj_t * label_bat = lv_label_create(ext->bat_cont, NULL);
    lv_obj_set_style_local_text_font(label_bat, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_BIG);
    uint8_t bat_status = Hal_Battery_Get_Status();
    exercise_set_bat_label(label_bat, bat_status);

    lv_obj_t * label_bat_percent = lv_label_create(ext->bat_cont, NULL);
    lv_obj_set_style_local_text_font(label_bat_percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                     LV_THEME_WATCH_NIGHT_FONT_SMALL);
    lv_obj_set_style_local_text_letter_space(label_bat_percent, LV_LABEL_PART_MAIN,
                                             LV_STATE_DEFAULT, 0);
    char str[10];
    snprintf(str, 10, "%02d%%", bat_status);
    lv_label_set_text(label_bat_percent, str);
    lv_watch_set_free_num(ext->bat_cont, bat_status);

    lv_obj_align(ext->bat_cont, ext->time_label, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);

    lv_bidi_dir_t dir = lv_obj_get_base_dir(bg);

    lv_coord_t y_offset = font_h / 16;
    lv_obj_t * heart_img = lv_img_create(bg, NULL);
    lv_img_set_auto_size(heart_img, true);
    lv_img_set_src(heart_img, ICON_HEART_RATE_HEART);
    lv_coord_t big_img_h = exercise_set_heart_zoom(heart_img);
    lv_coord_t space_hor = (2 * space - lv_obj_get_width(heart_img)) / 3;
    if(LV_BIDI_DIR_RTL == dir) {
        lv_obj_align(heart_img, bg, LV_ALIGN_IN_LEFT_MID, 2 * space_hor, -big_img_h / 2 + y_offset);
    } else {
        lv_obj_align(heart_img, bg, LV_ALIGN_IN_RIGHT_MID, -2 * space_hor, -big_img_h / 2 + y_offset);
    }

    lv_anim_t a = {};
    lv_anim_init(&a);
    lv_anim_set_var(&a, heart_img);
    lv_anim_set_start_cb(&a, exercise_heart_anim_cb);
    lv_anim_set_time(&a, 500);
    lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
    lv_anim_start(&a);

    ext->hr_label = lv_label_create(bg, ext->time_label);
    lv_obj_set_width(ext->hr_label, big_img_h + 4);
    lv_obj_align(ext->hr_label, heart_img, LV_ALIGN_OUT_BOTTOM_MID, 0,
                 big_img_h / 2 - lv_obj_get_height(heart_img) / 2);

    ext->note_label = lv_label_create(bg, ext->time_label);
    lv_obj_set_style_local_text_line_space(ext->note_label, LV_LABEL_PART_MAIN,
                                           LV_STATE_DEFAULT, 0);
    lv_label_set_long_mode(ext->note_label, LV_LABEL_LONG_BREAK);
    lv_obj_set_width(ext->note_label, LV_HOR_RES * 2 / 3);
    if(is_wait_gps) {
        ext->gps_cont = lv_cont_create(bg, ext->bat_cont);
        lv_coord_t gps_signal_cont_w = font_h / 6;
        lv_coord_t gps_signal_cont_h = font_h * 3 / 4;
        lv_obj_set_height(ext->gps_cont, gps_signal_cont_h);
        lv_obj_set_style_local_pad_inner(ext->gps_cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                         gps_signal_cont_w);
        lv_cont_set_layout(ext->gps_cont, LV_LAYOUT_ROW_BOTTOM);

        lv_obj_t * gps_signal_cont[3];
        gps_signal_cont[0] = lv_cont_create(ext->gps_cont, NULL);
        lv_obj_set_size(gps_signal_cont[0], gps_signal_cont_w, gps_signal_cont_h / 2);
        lv_obj_set_style_local_bg_opa(gps_signal_cont[0], LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                      LV_OPA_COVER);
        lv_obj_set_style_local_bg_color(gps_signal_cont[0], LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                        LV_COLOR_GRAY);
        lv_obj_set_style_local_radius(gps_signal_cont[0], LV_CONT_PART_MAIN, LV_STATE_DEFAULT,
                                      gps_signal_cont_w / 4);

        gps_signal_cont[1] = lv_cont_create(ext->gps_cont, gps_signal_cont[0]);
        lv_obj_set_height(gps_signal_cont[1], gps_signal_cont_h * 3 / 4);

        gps_signal_cont[2] = lv_cont_create(ext->gps_cont, gps_signal_cont[1]);
        lv_obj_set_height(gps_signal_cont[2], gps_signal_cont_h);

        space_hor = (2 * space - lv_obj_get_width(ext->gps_cont)) / 3;
        if(LV_BIDI_DIR_RTL == dir) {
            lv_obj_align(ext->gps_cont, bg, LV_ALIGN_IN_RIGHT_MID, -2 * space_hor,
                         -gps_signal_cont_h / 2 - 2 * y_offset);
        } else {
            lv_obj_align(ext->gps_cont, bg, LV_ALIGN_IN_LEFT_MID, 2 * space_hor,
                         -gps_signal_cont_h / 2 - 2 * y_offset);
        }
        lv_watch_set_free_num(ext->gps_cont, 0);

        lv_anim_set_var(&a, ext->gps_cont);
        lv_anim_set_start_cb(&a, exercise_gps_anim_cb);
        lv_anim_set_time(&a, 400);
        lv_anim_start(&a);

        lv_obj_t * gps_label = lv_label_create(bg, NULL);
        lv_obj_set_style_local_text_font(gps_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT,
                                         LV_THEME_WATCH_NIGHT_FONT_SMALL);
        lv_obj_set_style_local_text_letter_space(gps_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 0);
        lv_label_set_text(gps_label, "GPS");
        lv_obj_align(gps_label, ext->gps_cont, LV_ALIGN_OUT_BOTTOM_MID, 0, 3 * y_offset);

        lv_label_set_text_id(ext->note_label, WATCH_TEXT_ID_POSITIONING_AND_WAIT);
    } else {
        ext->gps_cont = NULL;

        lv_label_set_text_id(ext->note_label, WATCH_TEXT_ID_READY_AND_CLICK_TO_START);
    }
    lv_coord_t below_btn_h = LV_VER_RES - lv_obj_get_y(btn) - lv_obj_get_height(btn) - space_ver;
    if(below_btn_h <= lv_obj_get_height(ext->note_label)) {
        lv_obj_align(ext->note_label, btn, LV_ALIGN_OUT_BOTTOM_MID, 0, -space_ver);
    } else {
        lv_obj_align(ext->note_label, btn, LV_ALIGN_OUT_BOTTOM_MID, 0, space_ver);
    }

    hal_rtc_t time;
    Hal_Rtc_Gettime(&time);
    if(12 < time.tm_hour) {
        snprintf(str, 10, "%02d:%02d PM", time.tm_hour - 12, time.tm_min);
    } else {
        snprintf(str, 10, "%02d:%02d AM", time.tm_hour, time.tm_min);
    }
    lv_label_set_text(ext->time_label, str);

    lv_label_set_text(ext->hr_label, "--");

    ext->update_task = lv_task_create(exercise_sport_preparation_update_task_cb, 1000,
                                      LV_TASK_PRIO_HIGH, ext);
}

/**********************
 *   GLOBAL FUNCTIONS
 ***********************/
void exercise_main_sport_cb(lv_obj_t * btn, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;

    printf("%s\n", __FUNCTION__);

    lv_obj_t * label = lv_obj_get_child_back(btn, NULL);
    exercise_item_t * item = lv_watch_get_free_ptr(label);
    exercise_sport_info_t sport_info;
    exercise_get_sport_info(item->type, &sport_info);
    exercise_sport_preparation_create(item, sport_info.is_wait_gps, sport_info.img_src);
    exercise_sport_prepare_req(item->type);
    if(0 != (sport_info.setting_item_bitmap & (1 << EXERCISE_SETTING_ITEM_TYPE_WAKEY))) {
        exercise_nv_wakey_t * nv
            = (exercise_nv_wakey_t *)exercise_get_nv_pointer(item->data,
                                                             sport_info.setting_item_bitmap,
                                                             EXERCISE_SETTING_ITEM_TYPE_WAKEY);
        if(nv->is_wakey) {
            watch_set_suspend_enable(false, ACT_ID_EXERCISE_SPORT, false);
        }
    }
}

bool exercise_sport_home_key_handle(void)
{
    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_EXERCISE_SPORT);
    if(NULL == activity_obj) return(false);

    lv_obj_t * obj = NULL;
    lv_watch_get_child_obj(activity_obj, lv_watch_obj_signal, &obj);
    if(NULL == obj) {
        // sport has been started
        exercise_sport_start_up_func_key_cb(activity_obj);
    } else {
        //sport is not started
        return(false);
    }
    return(true);
}

bool exercise_sport_back_key_handle(void)
{
    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_EXERCISE_SPORT);
    if(NULL == activity_obj) return(false);

    lv_obj_t * obj = NULL;
    lv_watch_get_child_obj(activity_obj, lv_watch_obj_signal, &obj);
    if(NULL == obj) {
        // sport has been started
        exercise_sport_start_down_func_key_cb(activity_obj);
    } else {
        //sport is not started
        exercise_sport_preparation_down_func_key_cb(obj);
    }
    return(true);
}

#endif /*USE_LV_WATCH_EXERCISE*/
